《深入了解Java虚拟机》笔记-jvm 类加载机制

一、类的初始化

主动引用:比较常见的场景有

1、使用new关键字去实例化一个对象,读取或者设置一个类的静态字段(被final修饰的静态常量除外,这样的字段会在编译阶段被放入常量池中,不会触发类的加载),调用一个类的静态方法。

2、使用java.lang.reflect的方法对类进行反射调用的时候,如果类没有被初始化,则会初始化这个类

3、当初始化一个子类的时候,如果其父类还没有进行初始化,则要先触发其父类的初始化。

4、虚拟机启动时会初始化程序的入口类(比如包含main方法的那个类)

以上的四种情形都是对类的主动引用,会触发类的初始化。

被动引用:

1、子类引用父类的静态变量,不会触发子类的初始化。对于一个静态变量,只有直接定义这个字段的类才会被初始化。

class Parent {
    static {
        System.out.println("parent init!");
    }
    protected static String val = "jvm";
}

class Child extends Parent{
    static {
        System.out.println("child init");
    }
}

public class InitDemo{
    public static void main(String[] args) {
        System.out.println(Child.val);
    }
}
结果为:
parent init!
jvm

子类没有被初始化

2、常量在编译阶段会被放入到调用类的常量池中,本质上没有直接引用到定义常量的类,不会触发定义常量的类的初始化

class Normal{
    public final static String str = "jvm";
    static {
        System.out.println("Normal init");
    }
}

public class ConstantDemo {
    public static void main(String[] args) {
        System.out.println(Normal.str);
    }
}
结果为:
jvm

Normal 类并没有被初始化

上面的代码在执行过程中并没有输出Normal init,虽然ConstantDemo 在源码中引用了Normal类的常量str,但是在编译阶段此常量的值"jvm"存储到了ConstantDemo的常量池中,对常量Normal.str的引用转化成ConstantDemo对于自身常量池的引用了,因此不会触发Normal 类的初始化。

猜你喜欢

转载自www.cnblogs.com/wbringarden/p/9710862.html