一个java类的完整的生命周期会经历加载、连接、初始化、使用、卸载五个阶段。
也存在没有经历过初始化直接使用的情况。
1、加载就是找到需要加载的类,把类的信息加载到jvm的方法区中,在堆区中实例化一个java.lang.Class对象,作为方法区中这个类的信息入口。
加载类的两种方式:1、根据类的全路径名找到相应的class文件,从class文件中读取
2、从jar包文件中读取
2、连接可以细分为三个步骤:验证、准备、解析
验证:即验证加载类的合法性、规范性,判断它能否被jvm所运行
准备:为类的静态变量分配内存,并设为jvm默认的初值(基本类型初值为0,默认类型初值为null),对于非静态变量不分配内存。常量也会被分配内存,常量的默认值是程序中设定的值。
解析:把常量池中的符号引用转换为直接引用。即在未解析前,加载的所有类或接口及里面的属性、方法信息在jvm中只是用一个标识来标记的,执行解析后可以查看到这些信息的具体的内存地址。
连接阶段完成后会根据类的使用情况(直接引用还是被动引用)来选择是否对类进行初始化
3、初始化发生在类被直接引用的情形下。
类的初始化过程:按照顺序自上而下运行类中的变量赋值语句和静态语句,如果有父类,则首先按照顺序运行父类中的变量赋值语句和静态语句。 也就是说只会初始化与类相关的静态赋值语句和静态语句,即static关键字修饰的信息,没有static修饰的赋值语句和执行语句都在实例化对象的时候才会运行。
4、使用主要分为主动引用和被动引用
直接引用(主动引用)四种情况:
- 通过new关键字实例化对象、读取或设置类的静态变量、调用类的静态方法。
- 通过反射方式执行以上三种行为。
- 初始化子类的时候,会触发父类的初始化。
- 作为程序入口直接运行时(也就是直接调用main方法)。
- 引用父类的静态字段,只会引起父类的初始化,而不会引起子类的初始化。
- 定义类数组,不会引起类的初始化。
- 引用类的常量,不会引起类的初始化。
类卸载的三个条件:
- 该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。
- 加载该类的ClassLoader已经被回收。
- 该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
