类的初始化,包括生成对象的初始化和类的静态块的实例化。
初始化触发的时机: 类被直接引用(主动引用)的时候。
主动引用
主动引用的情形有:
1. 使用new关健字实例化对象
2. 使用类的静态变量
3. 使用类的静态方法
4. 使用反射机制调用上述操作
5. 程序入口 (调用main方法)
初始化顺序是:
静态块 ---> 非静态块 ---> 构造函数。
如果有超类,则初始化顺序是:
父类静态块--->子类静态块--->父类非静态块--->父类构造函数--->子类非静态块--->子类构造函数
Example:
public class ObjectInitialTest {
public static void main(String[] args) {
System.out.println("---Initialize new Class---");
Father c = new Child();
System.out.println("---Execute chlid class method---");
Child.execute();
}
}
class Child extends Father {
static {
System.out.println("Child static block");
}
{
System.out.println("Child block");
}
public Child(){
System.out.println("Child created");
}
public static void execute() {
System.out.println("Child execute");
}
}
class Father {
static {
System.out.println("Father static block");
}
{
System.out.println("Father block");
}
public Father(){
System.out.println("Father created");
}
}
执行Father c = new Child()输出为:
---Initialize new Class---
Father static block
Child static block
Father block
Father created
Child block
Child created
执行Child.execute()输出为:
---Execute chlid class method---
Father static block
Child static block
Child execute
执行 Father c = new Child();Child.execute();输出:
---Initialize new Class---
Father static block
Child static block
Father block
Father created
Child block
Child created
---Execute child class method---
Child execute
由上述结果可知,类的静态块,只初始化一次。
结论:
在类的初始化时,只会初始化类的静态块和静态赋值语句,也就是static修饰的代码块,没有static修饰的代码块在对象实例化时才执行。
被动引用
被动引用不会触发类的初始化。
被动引用的情形:
1.引用父类的静态字段,只会初始化父类,不会初始化子类。
2.引用类的常量,不会引起类的初始化。
类的卸载
在类使用完之后,满足下面的情形,会被卸载:
1. 该类在堆中的所有实例都已被回收,即在堆中不存在该类的实例对象。
2. 加载该类的classLoader已经被回收。
3. 该类对应的Class对象没有任何地方可以被引用,通过反射访问不到该Class对象。
如果类满足卸载条件,JVM就在GC的时候,对类进行卸载,即在方法区清除类的信息。
总结
Java的类对象基本上都是在jvm的堆区中创建,在创建对象之前,会触发类加载(加载、连接、初始化),当类初始化完成后,根据类信息在堆区中实例化类对象,初始化非静态变量、非静态代码以及默认构造方法,当对象使用完之后会在合适的时候被jvm垃圾收集器回收。
对象的生命周期只是类的生命周期中使用阶段的主动引用的一种情况(即实例化类对象)。而类的整个生命周期则要比对象的生命周期长的多。