类(class)和对象(object)是面向对象的核心概念。
类是对一类事物描述,是抽象的、概念上的定义。
对象是实际存在的某类事物的某个个体,因而也称实例(instance)。
类与类的关系
Field 字段 = 属性 = 成员变量
Method = (成员)方法 = 函数
Constructor 构造器
初始化块(代码块)
作用:对Java对象进行初始化
类的加载顺序:
(1) 父类静态代码块(包括静态初始化块,静态属性,但不包括静态方法)
(2) 子类静态代码块(包括静态初始化块,静态属性,但不包括静态方法 )
(3) 父类非静态代码块( 包括非静态初始化块,非静态属性 )
(4) 父类构造函数
(5) 子类非静态代码块 ( 包括非静态初始化块,非静态属性 )
(6) 子类构造函数
内部类
new 父类构造器(实参列表) | 实现接口(){
//匿名内部类的类体部分
}
定义内部类:
class Person{
// 成员内部类 (非static的)
class Bird{}
//成员内部类 (静态内部类)
static class Dog{}
}
创建内部类的对象:
//创建静态内部类的对象:可以直接通过外部类调用静态内部类的构造器
Person.Dog d = new Person.Dog();
//创建非静态的内部类的对象:必须先创建外部类的对象,通过外部类的对象调用内部类的构造器
Person p = new Person();
Person.Bird b = p.new Bird();
区分内部类、外部类的变量:
public class A{
private int s = 111;
public class B {
private int s = 222;
public void mb(int s) {
System.out.println(s); // 局部变量s
System.out.println(this.s); // 内部类对象的属性s
System.out.println(A.this.s); // 外层类对象属性s
}
}
}
public class TestOOP {
public static void main(String[] args) {
// 2. 创建类的实例(对象)
Animal nAnimal = new Animal("猴子", 1);
// 调用类的属性或方法
nAnimal.eat();
System.out.println(nAnimal.getName());
}
}
// 1. 设计并定义类
class Animal{
// 属性
private String name;
public int age;
// 构造器
public Animal() {}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
// 方法
public void eat() {
System.out.println(name + "进食");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
// 代码块
{
System.out.println("??");
}
}
public、protected、private置于类的成员定义前,用来限定对象对该类成员的访问权限。
修饰符 | 类内部 | 同一个包 | 子类 | 任何地方 |
---|---|---|---|---|
private | Yes | |||
(缺省) | Yes | Yes | ||
protected | Yes | Yes | Yes | |
public | Yes | Yes | Yes | Yes |
总结:
对于class的权限修饰只可以用public和default(缺省)。
public void test(int i, String...strs){
// 可将strs看做数组
}
public class Person {
public String name;
public int age;
public Date birthDate;
public String getInfo() {...}
}
public class Student extends Person{
public String school;
}
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
此处的多个类称为子类,单独的这个类称为父类(基类或超类)。可以理解为:“子类 is a 父类”。语法:
class Subclass extends Superclass{ }
在子类中可以根据需要对从父类中继承来的方法进行改造。
在程序执行时,子类的方法将覆盖父类的方法。
package mytest;
public class A{
private void privateFunc() {
System.out.println("A privateFunc");
}
void defaultFunc() {
System.out.println("A defaultFunc");
}
protected void protectedFunc() {
System.out.println("A protectedFunc");
}
public void publicFunc() {
System.out.println("A publicFunc");
}
}
package mytest;
public class B extends A{
// 不是重写,而是定义了另外一个函数,重写的前提是有访问权限
private void privateFunc() {
System.out.println("B privateFunc");
}
// 重写
void defaultFunc() {
System.out.println("B defaultFunc");
}
// 重写
protected void protectedFunc() {
System.out.println("B protectedFunc");
}
// 重写
public void publicFunc() {
System.out.println("B publicFunc");
}
}
package mytest;
public class Test {
public static void main(String[] args) {
A a = new B();
B b = new B();
// a.privateFunc(); // 只能在类内部调用
a.defaultFunc();
a.protectedFunc();
a.publicFunc();
// b.privateFunc(); // 只能在类内部调用
b.defaultFunc();
b.protectedFunc();
b.publicFunc();
}
}
输出:
B defaultFunc
B protectedFunc
B publicFunc
B defaultFunc
B protectedFunc
B publicFunc
体现:
Java引用变量有两个类型:编译时类型和运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。
若编译时类型和运行时类型不一致,就出现多态.
子类可看做是特殊的父类,所以父类类型的引用可以指向子类的对象:向上转型(upcasting)。
一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法。
// B继承A
A a = new B(); // 向上转型
a.defaultFunc(); // 虚拟方法调用(Virtual Method Invocation)
//a.bfunc(); // 无法调用子类中添加的方法
((B)a).bFunc(); // 强制类型转换(向下转型)
它在方法内部使用,表示这个方法所属对象的引用;
它在构造器内部使用,表示该构造器正在初始化的对象的引用。
可以调用属性、方法、构造器(构造器相互调用,使用this()必须放在构造器的首行)。
super可用于访问父类中定义的属性、成员方法,在子类构造方法中调用父类的构造器。
注意:
包帮助管理大型软件系统:将语义近似的类组织到包中;解决类命名冲突的问题。
package语句作为Java源文件的第一条语句,指明该文件中定义的类所在的包。(若缺省该语句,则指定为无名包)。
格式为:
package 顶层包名.子包名
import 包名[.子包名…]. <类名 |*>
若引入的包为:java.lang,则编译器默认可获取此包下的类,不需要再显示声明。
可以使用import lee.* ;语句,表明导入lee包下的所有类。而lee包下sub子包内的类则不会被导入。
import static java.lang.System.out
import static java.lang.System.*
修饰属性(类变量)、方法(类方法)、初始化块(代码块)、内部类。
被修饰后的成员具备以下特点:
类变量存在于静态域中。
static方法即使被重写,也不能通过父类的指针(多态)访问到子类重写的static方法。
A a1 = new B();
a1.staticFunc(); // A staticFunc
((B)a1).staticFunc(); // B staticFunc
单例模式
单例模式的几种实现方式#java,简单易懂
修饰类、属性和方法。
注意:final修饰对象时,其引用不能改变,但对象内部的属性若没有用final修饰,则可以被修改。
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2);//false
System.out.println(str1.equals(str2));//true
System.out.println(“hello” == new java.sql.Date()); //编译不通
字符串常量池:Person p1 = new Person();
p1.name = "atguigu";
Person p2 = new Person();
p2.name = "atguigu";
System.out.println(p1.name.equals(p2.name));//true
System.out.println(p1.name == p2.name);//true
String string3 = "string";
String string4 = "string";
System.out.println(string3 == string4);//true
System.out.println(string3.equals(string4));//true
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
像String类、包装类、File类、Date类等,已经实现了Object类中toString()方法的重写。针对八种基本定义相应的引用类型—包装类(封装类)
基本数据类型 | 包装类 |
---|---|
boolean | Boolean |
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
float | Float |
double | Double |
基本数据类型包装成包装类的实例。
int i = 50;
Integer t = new Integer(i);
Float f = new Float(“4.56”);
Long l = new Long(“asdf”); //NumberFormatException
获得包装类对象中包装的基本类型变量。
调用包装类的.xxxValue()方法
Boolean boolean1 = true;
boolean b = boolean1.booleanValue();
// 通过包装类的构造器实现
int i = new Integer(“12”);
// 通过包装类的parseXxx(String s)静态方法
Float f = Float.parseFloat(“12.1”);
// 调用字符串重载的valueOf()方法
String fstr = String.valueOf(2.34f);
// 调用包装类的toString()方法
String s1 = Integer.toString(314);
// 更直接的方式
String intStr = 5 + “”
JDK1.5之后,支持自动装箱,自动拆箱。但类型必须匹配。
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
abstract int abstractMethod(int a);
含有抽象方法的类必须被声明为抽象类。(即抽象类中才有的抽象方法)
抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
不能用abstract修饰属性、构造器、私有方法、静态方法、final的方法。
总结:abstract修饰的方法必须能够被子类重写。
模板方法设计模式(TemplateMethod)
有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
接口(interface)是抽象方法和常量值的定义的集合。
class SubClass implements InterfaceA{ }
接口中的所有成员变量都默认是由public static final修饰的。
接口中的所有方法都默认是由public abstract修饰的。
接口没有构造器。
接口采用多继承机制。
实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。
接口的主要用途就是被实现类实现。(面向接口编程)
与继承关系类似,接口与实现类之间存在多态性
public interface Runner {
int ID = 1;
void start();
public void run();
void stop();
}
实现接口的匿名类对象:
Runner r = new Runner(){
// 实现接口的所有方法
}
总结:接口可以看做一种特殊的抽象类,所有属性为公开静态常量,所有方法都为公开抽象方法。接口之间可以多继承,类可以实现多个接口。
如果抽象类和接口都可以使用的话,优先使用接口,因为避免单继承的局限。
在开发中,一个类不要去继承一个已经实现好的类,要么继承抽象类,要么实现接口。
工厂方法(FactoryMethod)模式
代理模式(Proxy)
注:以上笔记参考自尚硅谷