类加载器与类初始化深度剖析

之前已经对类初始化相关的东东进行了非常细致的学习,另外也对类加载器进行了初始的了解,其中对于类的主动方式会有七种,这里再来回顾一下:

这次做一些实验来进一步巩固关于类初始化相关的知识点,下面开始:

实验一:

为什么?如果彻底搞清楚了之前关于类初始化的知识点,那这个不难解释,原因是由于:FinalTest.x目前是个编译期常量,它会在编译期间将其放到常量池,并不会导到FinalTest的主动使用,为了更进一步能看清本质,咱们将MyTest8的字节码文件进行反编译,如下:

好下面继续改造:

它是属于七种主动使用类的情况之一,如下:

接着再来修改:

此时继续反编译一下:

实验二:

为什么是按这样一个顺序输出的呢?由于使用到了main()静态方法,所以会导致MyTest9的主动使用,所以"MyTes9 static block"会被初始化,其原因还是七种主动使用的情况之一,如下:

接着由于"Child.b"子类静态变量的使用会导到它的父类进行初始化,所以"Parent static block"输出了,最后自己再初始化,所以"Child static block"输出了,最终再输出要打印的变量的值,为了进一步查看类的加载信息,还是给JVM加上"-XX:+TrancClassLoading"参数来进行观测,如下:

实验三:

package com.jvm.classloader;

class Parent2 {
    static int a = 2;

    static {
        System.out.println("Parent2 static block");
    }
}

class Child2 extends Parent2 {
    static int b = 4;

    static {
        System.out.println("Child2 static block");
    }
}

public class MyTest10 {

    static {
        System.out.println("MyTest10 static block");
    }

    public static void main(String[] args) {
        Parent2 parent2;

        System.out.println("------------------");

        parent2 = new Parent2();

        System.out.println("------------------");

        System.out.println(parent2.a);

        System.out.println("------------------");

        System.out.println(Child2.b);
    }
}

编译运行:

这又是为何呢?分析一下:由于调用了main()方法,则MyTest10会被初始化,所以“MyTest10 static block”被输出了,而这个不会导致任何输出:

接着生成Parent2的实例则会导到它被初始化,如下:


而它对应这种主动使用的情况:

,所以"Parent2 static block"被输出了,接着输出Parent2.a,所以“3”就被输出出来了,最后这句话会导到Child2被初始化,如下:

照理在初始化子类的时候,应该先初始化父类Parent2,但是由于Parent2已经在之前初始化过了,所以这里就不会再次初始了,接着走Child2的初始化逻辑,于是乎“Child2 static block”就被打印出来了,最终再打印Child2.b值"4"。

实验四:

下面分析一下:由于Child3.a调用的是它父类Parent3里面的变量,所以也就是对Parent3的主动使用,于是乎就会打印出:

而接下来还是通过Child3去调用它父类的doSomething(),同样也不会导至Child3的初始化,而只会导致Parent3进行初始化,但是由于它之前已经被初始化了,所以输出为:

所以总结一下:如果用子类去访问父类的静态变量或静态方法,表示的是对于父类的主动使用,而非表示对子类的主动使用。

实验五:

这个实现会涉及到类加载器相关的东东,但是还是说明类初始化相关的知识点,具体如下:

其中可以发现通过系统加载类时是不会导致类的初始化的,而通过Class.forName是会导致类的初始化,其它这也对应七种主动使用的这种情况:

所以总结一下:调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,也就不会导致类的初始化。

posted on 2018-05-11 14:40  cexo  阅读(324)  评论(0编辑  收藏  举报

导航