Table of Contents
一、类的初始化时机
在《深入理解java虚拟机》这本书里面讲到了类的六个初始化时机
- 创建类的实例
- 访问类的静态变量(注意:当访问类的静态并且final修饰的变量时,不会触发类的初始化。),或者为静态变量赋值。
- 调用类的静态方法(注意:调用静态且final的成员方法时,会触发类的初始化!一定要和静态且final修饰的变量区分开!!)
- 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。如:Class.forName("********");注意通过类名.class得到Class文件对象并不会触发类的加载。
- 初始化某个类的子类
- 直接使用java.exe命令来运行某个主类(java.exe运行,本质上就是调用main方法,所以必须要有main方法才行)。
二、类初始化过程
1 一个类要创建实例需要先加载并初始化该类
- main方法所在的类需要优先加载和初始化
2 一个子类要初始化需要先初始化父类
3 一个类初始化就是执行clinit()方法
- clinit方法由静态类变量显示赋值代码和静态代码块组成,声明不属于,只有显示赋值才算。
- 类变量显示赋值代码和静态代码块从上到下顺序执行
- clinit方法只执行一次
三、实例初始化
1 实例初始化执行的事init方法
- init方法可能重载有多个,有几个构造器就有几个init方法
- init由非静态实例变量显示赋值代码和非静态代码块,对应构造器代码组成。
- 非静态实例变量显示赋值和非静态代码块按照顺序执行,构造器最后执行。
- 每次创建实例对象,调用对应的构造器,执行的就是对应init方法
- init方法首行是super()或者super(实例形参),即对应的父类的init方法
类初始化:先父类的初始化,后子类的初始化
实例初始化:每个init方法首行是super()或者super(实例形参),即对应的父类的init方法
父类的实例初始化:super(),父类非静态实例变量显示赋值,父类的非静态代码块,父类构造器
子类的实例初始化:super() ,子类非静态实例变量显示赋值,子类的非静态代码块,子类构造器。
HashMap<String, String> map =
new HashMap<String, String>() {// 匿名内部类创建
{ // 非静态代码块:在匿名内部类new的时候实例化非静态代码块,所以可以这样写,里面调用非静态方法
put("Name", "June");
put("QQ", "2572073701");
}
};
四、方法重写override
1 哪些方法不可以被重写
- final方法
- 静态方法
- private等子类不可见的方法
2 对象的多态性
- 子类如果重写了父类的方法,通过子类对象调用的一定是子类重写过的代码
- 非静态方法默认调用对象是this
- this对象在构造器或者说init()方法中就是正在创建的对象
五、静态结构和非静态结构
静态结构随着类加载初始化:所以
静态结构中不能调用非静态结构
非静态结构可以调用静态机构