深入理解java虚拟机-第四章:虚拟机类加载机制
一、类的生命周期
a) 生命周期:类从被加载到虚拟机中开始,到卸载出虚拟机为止。
b) 各个阶段
注:上图是类加载的各个阶段,绿框这5个阶段顺序是确定的,类加载的过程必须按照这个阶段开始(注意是开始,不是进行,各个阶段在进行时存在相互交叉混合的情况)
1)加载 : 虚拟机没有强制约束何时开始。
在此阶段,虚拟机完成三件事:
- 通过一个类的全限定名来获取定义此类的二进制字节流。
- 将这个流所代表的静态存储结构转变为 方法区的运行时 数据结构。
- 在java堆中生成一个代表此类的java.lang.class对象,作为方法区访问此对象的入口。
2)连接
- 验证:确保Class文件中的字节流所包含的信息是安全的。
- 准备:正式为类变量分配内存并设置类变量初始值。
- 解析:虚拟机将常量池中的符号引用改为直接引用。
3)初始化:真正开始执行类中定义的java代码。
在准备阶段已经赋予变量的初始值,将在这个阶段进行实际赋值。
有且只有4中情况需要对类进行初始化(加载、验证和准备阶段需要在此之前开始)--主动引用
- 使用new关键字实例化对象的时候;调用类的静态方法的时候;读取或设置一个类的静态属性的时候(被final修饰和已经放入常量池的除外)
- 对类进行反射调用的时候
- 对类进行初始化,但发现它继承的父类还没有初始化的时候。(接口除外)
- 虚拟机启动,需要指定一个执行主类的时候。
4)使用:不多说。
5)卸载:结束生命周期。
- 执行Sysem.exit();方法
- 程序正常运行结束。
- 程序抛出异常。
- 操作系统宕机。
public class SuperClass {
static{
System.out.println("super is init!");
}
static int value = 0;
}
public class SubClass extends SuperClass{
static{
System.out.println("SubClass init");
}
static final int value = 1;
}
public class Initlization {
public static void main(String[] args) {
System.out.println(SubClass.value);
//System.out.println(new SubClass());
//SuperClass[] x = new SuperClass[10];
}
}
解析:运行结果为1 .这里是被动引用。所获取的final修饰的变量已经在变量池中存在。
public class Test {
static Test t = new Test();
static int a ;
static int b = 0;
Test(){
a++;
b++;
}
public static Test getNewTest(){
return t;
}
public static void main(String[] args) {
t.getNewTest();
System.out.println(a);
System.out.println(b);
}
运行结果:
1
0
解析:开始的时候会以为是11;但结合类加载和赋值的顺序就可发现。
准备阶段:先加载等号左边的部分,并且赋予默认值。int的默认值为0;a和b执行++;得到的结果都是1.
再进行初始化,因为a在定义时并没有赋值,而b在定义阶段已经赋值为0;所以结果为1,0