类加载时机

2019-12-24  本文已影响0人  紫色红色黑色

面试题

public class A {

    static {
        System.out.println("static a");
    }

    {
        System.out.println("block a");
    }

    public static String name = "hello";
    public static final String WORLD = "world";

    public A() {
        System.out.println("construct a");
    }
}


public class B extends A {

    static {
        System.out.println("static b");
    }

    {
        System.out.println("block b");
    }

    public B() {
        System.out.println("construct b");
    }
}


public class ClassLoadingDemo {

    public static void main(String[] args) {

        B b = new B();
        B b2 = new B();
    }
}

输出结果

static a
static b
block a
construct a
block b
construct b
block a
construct a
block b
construct b

从结果可以看到:
1.类初始化发生在对象初始化之前;
2.类初始化只发生一次;
3.父类初始化先于子类初始化;
4.静态代码块>代码块>构造方法;

类加载时机

下面内容引用自《深入理解Java虚拟机》

主动引用

虚拟机规范规定有且只有5种情况必须对类进行初始化:
1.遇到new、getstatic、putstatic、invokestatic四个字节码指令时。对应的java场景是:new对象时、读取或设置类变量(被final修饰的常量除外)时、调用类的静态方法时。
2.java.lang.reflect包的方法对类进行反射调用时
3.初始化类时,发现其父类没有初始化,则先初始化父类
4.虚拟机启动时指定的main()所在的类,虚拟机先初始化该类
5.如果java.lang.invoke.MethodHandle实例最后解析的结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄。并且这个方法句柄所对应的类没有初始化时,则先触发初始化。

被动引用

1.通过子类引用父类的静态字段,不会触发子类初始化
代码以上述为基础

public static void main(String[] args) {
    System.out.println(B.name);
}

显示,jvm参数加上-XX:+TraceClassLoading查看加载的类,可以看到B也加载了。

static a
hello

2.通过数组来引用类,不会触发此类的初始化
下面代码可以加载A,但是不初始化类

public static void main(String[] args) {
    A[] a = new A[10];
}

3.常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化

public static void main(String[] args) {
    System.out.println(A.WORLD);
}

显示

world
上一篇 下一篇

猜你喜欢

热点阅读