【JVM】类初始化机制

一个类从准备加载到虚拟机的内存中,到从虚拟机中内存卸载这样的一个生命周期中,有以下几个过程:加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 ->卸载。

在《JVM虚拟机规范》中,并没有对加载的时机做严格控制,但是对初始化的时机做了严格的控制。在六种情况下,虚拟机必须对一个类做初始化操作。

其中有一种情况是:如果读取或者写入一个静态资源,那么这个静态资源所在的类应该被提前加载。

但存在一些边界条件在这类情况中:

  1. 一个子类继承了父类,那么也可以通过子类去读取父类的静态资源,此时子类不会被初始化。
  2. 静态资源被final修饰,此时这个类不会被初始化。

第一类情况:

public class ParentClass {

    static {
        System.out.println("I am father");
    }

    public void test() {
        System.out.println("Father tesst");
    }

    public static int value = 127;
}


--------

public class SubClass extends ParentClass{

    static {
        System.out.println("I am sub");
    }

}
--------

public class TestMain {
    public TestMain() {
    }

    public static void main(String[] argv) {
        System.out.println(SubClass.value);
    }
}

我们认为一个类被加载入虚拟机中,他首先会执行这个类中的静态方法。那么我们可以通过观察一个类的静态方法有没有被执行来判断这个类有没有被初始化。

按照示例代码运行主函数,发现输出结果为

I am father
127

子类没有被初始化,我们认为如果子类没有覆盖父类的值,那么这个静态资源应该归属父类。

第二种情况,我们将静态资源 value 用final修饰

public static final int value = 127;

重新运行代码,发现输出结果中少了静态方法执行的输出

127

查看主函数所在的编译文件

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

public class TestMain {
    public TestMain() {
    }

    public static void main(String[] argv) {
        System.out.println(127);
    }
}

发现直接被127这个值所代替,所以我猜测是常量池资源不属于类的资源,是在编译阶段就被优化了,所以不涉及到加载类静态资源的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值