一、static关键字
1.1 成员变量
1.1.1 静态成员变量:
1)由static修饰,在内存中只存在一份,只加载一次(当类被加载到方法区的时候,在堆内存中同步开辟的一块此类的静态变量区,由static修饰的静态成员变量就在此时被加载,且仅此加载一次),是属于类的,是被各个对象共享的。
2)访问格式为:类名.变量名。
3)什么时候用?例如在线人数等,所有对象共享的数据,就定义为静态成员变量。
1.1.2 实例成员变量:
1)没有static修饰,是属于对象的,每个对象各有一份。
2)访问格式为:对象.变量名。
3)什么时候用?例如名字、年龄等,每个对象的信息不同时,就定义为实例成员变量。
1.1.3 static修饰成员变量的内存原理图
1.2 成员方法
1.2.1 静态成员方法
1)由static修饰,属于类,和类同时被加载进方法区,是类和对象共享的。
2)访问格式:类名.方法名。
3)什么时候定义成静态方法?当方法完成的是通用功能,与对象无关,不需要调用对象的实例成员变量时定义成静态方法更能方便访问。例如求最大值,不需要访问对象的属性(即对象的实例成员变量),可定义为静态成员方法。
1.2.2 实例成员方法
1)无static访问,属于对象,创建对象时才会建立对实例成员方法的引用地址(即创建对象后才可访问)。
2)访问格式:对象名.方法名。
3)什么时候用实例成员方法:表示对象自己的行为,需要访问对象属性,则该方法必须定义为实例成员方法。
1.2.3 静态成员方法的内存机制
1.3 static修饰后,被访问的注意事项
1)静态方法中只能访问静态成员,不能直接访问实例成员,因为实例成员属于对象(但可以先创建对象,用对象访问,这事间接访问了实例成员变量)。
2)实例方法可以访问实例成员,也可以访问静态成员,因为静态成员是共享的。
3)静态方法中不能使用this,因为this代表当前对象,但静态方法是用类名调用,不涉及对象,也就无从代表。
1.4 代码块
1.4.1 静态代码块
1)由static关键字修饰,与类同时加载,自动触发且仅触发一次。
2)什么情况使用?可以用来初始化静态数据。
1.4.2 构造代码块(即实例代码块)
1)属于对象,每次创建对象时都会执行一次,且在构造器之前执行。
二、工具类
1)工具类全部由静态方法组成。
2)减少冗余代码,提高复用性。
3)由于工具类不需要创建对象,建议工具类的构造器私有化。
三、设计模式
3.1单例模式
单例类对外只能产生一个对象。
3.1.1饿汉单例模式
1)饿汉单例:在使用类获取对象之前,就已经准备好了对象。
2)如何设计?
// 1.构造器私有化
private E(){
}
// 2.定义静态变量存储对象(在类加载时就创建了对象)
public static E instance = new E;
3.1.2懒汉单例模式
1)懒汉单例:只在真正需要对象的时候才去创建一个对象。
2)如何设计?
// 1.构造器私有化
private E(){
}
// 2.定义私有化静态变量,默认值为null,内存中仅此一份
private static E instance;
// 3.提供一个方法返回一个单例对象
public static E getInstance(){
/*如果不存在一个对象才创建,一次保证此类对象的唯一性*/
if(instance == null){
instance = new E();
}
return instance;
}
四、继承
4.1 继承关系中,创建子类对象后的内存关系图
在堆内存中,对外是一个项目,对象内会划分父类和子类空间
4.2 继承的特点
4.2.1子类能否继承父类的构造器?
不能。
4.2.2 子类能否继承父类的私有成员?
有争议,但我认为能继承,只是不能直接访问。
4.2.3 子类能否继承父类的静态成员?
有争议。但我认为不能继承,仅仅是可以使用。因为静态成员仍属于父类,只是共享给子类使用。
4.2.4 Java支持多继承吗?
不支持。一个类不能继承多个类,但可以多层继承。其中Object类是所有类的父类。
4.3 继承后访问成员变量和成员方法的特点
遵循就近原则:现在子类局部中寻找---->再到子类成员中找---->再到父类中找。
4.3.1 super关键字
在子类与父类成员有重名时,根据就近原则会直接调用子类的变量或方法,若要指定调用父类的变量或方法,则使用super关键字。
4.3.2 this关键字
-
在局部变量和成员变量有重名时,根据就近原则会直接使用局部变量,若要指定使用成员变量,则使用this关键字。
-
this(…) ,在构造器中调用本类其他构造器。常见于创建对象时不提供所有参数就使用默认参数的情况。
public class E{ private String a; private String b; public E(String a){ this(a,"默认值b");//此时默认的super()已经没有了。 } public E(String a, String b){ // 这里会默认调用父类构造器。 this.a = a; this.b = b; } }
-
this(…)和super(…)都必须放在构造器第一行,所以二者不能共存于同一个构造器。
4.4 方法重写
- 子类与父类中一模一样的方法定义,称为方法重写。当子类需要某功能,但父类的功能不能完全解决子类的需要,子类可以重写父类方法,并扩展其功能。
- 重写方法的命名、参数列表需要与被重写方法完全一致。
- @override注解,加在重写方法上,可以校验重写语法是否正确,并加强代码可读性。
- 私有方法和静态方法不能被重写。
4.5 继承后子类构造器的特点
-
子类的全部构造器执行前,父类的无参构造器一定会被调用一次。
public E(){ //默认调用父类构造器 super(); } public E(int a){ //默认调用父类构造器 super(); }
-
子类中调用父类有参构造器
-
调用方法:使用super为继承自父类的属性赋值。
-
有何作用?
提高代码复用性:子类们公共的成员可以仅在父类中定义一次。
提高代码简洁性:创建子类对象时可以直接初始化数据,不必多次调用set方法为对象属性赋值。
-
五、权限修饰符
六、final关键字
- 修饰类:该类不能被继承。例如工具类。
- 修饰方法:该方法不能被重写。
- 修饰变量:该变量第一次赋值后不能被改写。
- 修饰的变量为基本数据类型:数据值不能被二次赋值。
- 修饰的变量为引用数据类型:变量存储的地址值不能改变,但地址指向的内容是可以随意改变的。
七、常量
- 常量是使用 public static final 修饰的变量,必须有初始值,不能被改变。
- 常量的命名规则:英文单词全部大写,多单词用下划线连接。
- 常量的修饰:用于做系统配置信息,方便牵一发动全身的修改。且在编译时常量会进行宏替换,使用常量的地方会编译成字面量,程序性能和直接使用字面量一样好。
八、枚举
-
定义格式:第一行罗列枚举类实例名。
public enum Season(){ APRING,SUMMER,AUTUMN,WINTER; }
-
枚举类不能被继承,且不能对外创建对象。
-
相对于常量而言,枚举类更适合做信息标志和分类,因为枚举类能对入参做出约束。
九、抽象类
-
抽象类的声明和注意事项:
-
abstract修饰的类成为抽象类
public abstract class E{ }
-
abstract修饰的方法称为抽象方法
public abstract void function();
-
注意:
- 抽象方法不能有方法体。
- 抽象方法必须放在抽象类中。
- 继承一个抽象类则必须实现其全部抽象方法,或者将此类也定义为抽象类。
- 不论抽象类中是否有抽象方法,抽象类一定不能创建对象。
-
-
抽象类的使用场景:
当父类要求其子类一定要完成某些功能,但子类对此行为的实现不完全相同时,可将父类定义为抽象类。此时这个抽象类可以定义公共代码提高复用性,又可以约束其子类必须实现某些功能。例如将动物类定义为抽象类,其中定义抽象方法“跑”,那么继承动物类的猫类和狗类就必须实现“跑”的功能,但又可以跑的不同。
-
final和abstract的关系
互斥关系:
final修饰类,该类不能被继承;abstract修饰类就是为了被继承。
final修饰方法,该方法不能被重写;abstract修饰方法,此方法必须被重写。