zoukankan      html  css  js  c++  java
  • 类加载器与类初始化深度剖析

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

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

    实验一:

    为什么?如果彻底搞清楚了之前关于类初始化的知识点,那这个不难解释,原因是由于: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方法加载一个类,并不是对类的主动使用,也就不会导致类的初始化。

  • 相关阅读:
    iOS截取http/https流量
    Jenkins拾遗--第五篇-git插件填坑
    Jenkins拾遗--第三篇(用户权限管理)
    Jenkins拾遗--第四篇-适当的让构建失败
    Jenkins拾遗--第二篇(初步配置Jenkins)
    Jenkins拾遗--第一篇(安装Jenkins)
    一个测试人员的2015的回顾和2016年展望
    xcode升级导致git无法使用
    在intellj idea下用sbt的坑
    本人已转战知乎,此处不玩了。
  • 原文地址:https://www.cnblogs.com/webor2006/p/9024560.html
Copyright © 2011-2022 走看看