java虚拟机规定必须立即初始化类的5种情况

Java类加载机制中,规定了有且仅有5种情况必须立即对类进行初始化(而加载,验证,准备自然再次之前):
1. 遇到new,getstatic,putstatic和invokestatic这4条指令时,如果类没有初始化时,必须初始化类。四条指令对应我们日常所见的 使用new关键字实例化对象,读取一个类的静态字段,设置一个类的静态字段(被final修饰的静态字段除外,因为已在编译期把结果放入常量池中了)和调用一个类的静态方法。

2. 对类进行反射调用时。

3. 当初始化一个子类时,发现其父类没有初始化,则需先出发其父类的初始化。

4. 当虚拟机启动时,一个类包含main()方法时,当前类需要初始化

5. 但是用动态语言支持时,如果一个java.lang.invoke.MethodHandle实例后解析结果REF_putStatic,REF_getStatic,REF_invokeStatic的方法句柄时,当改方法句柄对应的类没有初始化时,需要初始化该类。(动态语言支持详情请查看)

初次之外所有引用类的地方都不会出发类初始化,被称为被动应用,下面举三个例子:

1. 通过子类应用父类静态字段,不会导致子类初始化,代码如下:

package com.sun.jojo.noinitclass;
public class SuperClass {
    static {
        System.out.println("SuperClass Init !!!");
    }
    public static int value = 123;
}

package com.sun.jojo.noinitclass;
public class SubClass extends SuperClass{
    static {
        System.out.println("SubClass Init !!!");
    }
}

package com.sun.jojo.noinitclass;
public class NotInitialization {
    public static void main(String[] args) {
        System.out.println(SubClass.value);
    }
}

结果:
SuperClass Init !!!
123

结果只输出了”SuperClass Init !!!”, “SubClass Init !!!”没有出来,对应静态字段,只有直接定义改字段的类才会初始化。

2 .通过数组定义来引用类,不会出发此类的初始化,代码如下:

package com.sun.jojo.noinitclass;
public class NotInitialization {
    public static void main(String[] args) {
        //System.out.println(SubClass.value);
        SuperClass[] superClasses = new SuperClass[10];
    }
}

运行结果并没有打印出”SuperClass Init !!!”,这里并没有出发com.sun.jojo.noinitclass.SuperClass类的初始化.这里触发了另一个名为“[Lcom.sun.jojo.noinitclass.SuperClass”的类的初始化,他是虚拟机自动创建的,直接继承于java.lang.Object的子类,创建动作由字节码指令newarray触发。

3.常量在编译期间就会调入类的常量池中,本质上没有直接引用的定义变量的类,因此使用常量字段时不会触发累的初始化。

public class ConstClass {
    static {
        System.out.println("ConstClass Init !!!");
    }
    public static final int value = 123;
}

public class NotInitialization {
    public static void main(String[] args) {
        //System.out.println(SubClass.value);
        //SuperClass[] superClasses = new SuperClass[10];
        System.out.println(ConstClass.value);
    }
}

结果:只打印出123 “ConstClass Init !!!”并没有打印出来。

接口的初始化和类的初始化类似,区别在于5种中的第三种:当一个子类的初始化过程中需要去报其父类也必须先初始化,但接口初始化时不要求其父接口也进行初始化,只有在用到父接口时,才去初始化。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值