加载顺序总结
父类的静态字段——>父类静态代码块——>子类静态字段——>子类静态代码块——>
父类成员变量(非静态字段)——>父类非静态代码块——>父类构造器——>子类成员变量——>子类非静态代码块——>子类构造器
- 遇到 new、getstatic、putstatic、invokestatic 这四条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令的最常见的Java代码场景是:使用new关键字实例化对象的时候、读取或设置一个类的静态字段(被final修饰、已在编译器把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。
- 使用 java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
- 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
- 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。
JVM 对 Book 类进行初始化首先是执行类构造器(按顺序收集类中所有静态代码块和类变量赋值语句就组成了类构造器),后执行对象的构造器(按顺序收集成员变量赋值和普通代码块,最后收集对象构造器,最终组成对象构造器 )。
- 确定类变量的初始值。在类加载的准备阶段,JVM 会为类变量初始化零值,这时候类变量会有一个初始的零值。如果是被 final 修饰的类变量,则直接会被初始成用户想要的值。
- 初始化入口方法。当进入类加载的初始化阶段后,JVM 会寻找整个 main 方法入口,从而初始化 main 方法所在的整个类。当需要对一个类进行初始化时,会首先初始化类构造器(),之后初始化对象构造器()。
- 初始化类构造器。JVM 会按顺序收集类变量的赋值语句、静态代码块,最终组成类构造器由 JVM 执行。
- 初始化对象构造器。JVM 会按照收集成员变量的赋值语句、普通代码块,最后收集构造方法,将它们组成对象构造器,最终由 JVM 执行
自己总结
准备
1.为静态变量分配内存,并默认初始化
初始化
2.初始化
初始化步骤
1.假如这个类还没有被加载和连接,那就先进行加载和连接。
2.假如类存在直接的父类,并且这个父类还没有被初始化,那就先初始化直接的父类。
3.假如类中存在初始化语句,那就依次执行这些初始化语句。
初始化条件
(1) 主动引用
- 含有main()函数的类
- 创建类的实例,实例化(会调用构造函数,普通代码块,初始化类成员变量)
- 访问某个类的接口或静态变量,或者对静态变量赋值(只初始化类的静态变量和静态代码块)
- 调用类的静态方法(只初始化类的静态变量和静态代码块)
- 反射
- 初始化一个类的子类
静态变量只初始化一次
静态代码块:用staitc声明,jvm加载类时执行,仅执行一次,只能访问定义在其之前的变量
构造代码块:类中直接用{}定义,每一次创建对象时执行。
执行顺序优先级:静态块,main(),构造块,构造方法。
(2) 被动引用 - 子类调用父类静态字段,静态方法,子类不会初始化
- 数组定义引用类
- final修饰的静态常量
类加载器
双亲委派模型
类加载器
- 引导类加载器(Bootstrap ClassLoader):最顶层的加载类,主要加载核心类库
- 扩展类加载器(Extensions ClassLoader):
- 系统类加载器(System ClassLoader):加载当前项目下的类
- 自定义类加载器
参考文章
类加载器层级关系
重新loadClass类可自定义类加载器,破坏双亲委派机制
网友评论