• JVM实战-JVM之类加载时机


    JVM实战-JVM之类加载时机

    Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被称作虚拟机的类加载机制。

    关于在什么情况下需要开始类加载过程的第一个阶段“加载”,《Java虚拟机规范》中并没有进行强制约束,这点可以交给虚拟机的具体实现来自由把握。但是对于初始化阶段,《Java虚拟机规范》则是严格规定了有且只有六种情况必须立即对类进行“初始化”(初始化必然要先加载)。

    Java程序对类的使用分为主动引用和被动引用,针对上述六种情况,对于这六种会触发类型进行初始化的场景,《Java虚拟机规范》中使用了一个非常强烈的限定语——“有且只有”。

    1 主动引用

    主动引用的六种情况:

    1. 遇到new、getstatic、putstatic或invokestatic这四条字节码指令时,如果类型没有进行过初始化,则需要先触发其初始化阶段。能够生成这四条指令的典型Java代码场景有:
      • 使用new关键字实例化对象的时候。
      • 访问某个类或者接口的静态变量,或者对该静态变量进行赋值(被final修饰的静态变量、已在编译期间进入常量池的静态字段除外)。
      • 调用一个类型的静态方法的时候
    2. 使用java.lang.reflect包的方法对类型进行反射调用的时候,如果类型没有进行过初始化,则需要先触发其初始化。
    3. 当初始化类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
    4. 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。
    5. 当使用JDK 7新加入的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果为REF_getStaticREF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种类型的方法句柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化。
    6. 当一个接口中定义了JDK 8新加入的默认方法(被default关键字修饰的接口方法)时,如果有这个接口的实现类发生了初始化,那该接口要在其之前被初始化。
    /**
     * FileName: ClassInitTest
     * Author:   lxg
     */
    public class ClassInitTest {
        public static void main(String[] args) {
            // 1. 创建实例
            InitTest1 it1 = new InitTest1();
            // 2. 访问静态属性
    //        System.out.println(InitTest1.n);
            // 3. 调用静态方法
    //        InitTest1.method();
            // 4. 反射
    //        Class cls = Class.forName("classloder.initialization.InitTest1");
            // 5. 初始化子类
    //        InitTest2 it2 = new InitTest2();
            // 6. 启动类触发初始化,执行main()触发
            // 7. 跳过
            // 8. 当一个接口中的默认方法(被default关键字修饰的接口方法)初始化时,IfTestImpl初始化时会触发InitTest1 it1 = new InitTest1(),证明IfTest接口初始化
    //        IfTest ifTest = new IfTestImpl();
        }
    }
    
    // 类初始化会执行初始化类静态属性
    class InitTest1 {
        static {
            System.out.println("InitTest1初始化...");
        }
    
        public static int n = 10; // 静态变量
    
        public static void method() { // 静态方法
            n = 30;
        }
    }
    
    class InitTest2 extends InitTest1 {
        static {
            System.out.println("InitTest2初始化...");
        }
    }
    
    // 接口,验证第8条
    interface IfTest {
        InitTest1 it1 = new InitTest1();
    
        default void method() {
        }
    }
    
    class IfTestImpl implements IfTest {
        static {
            System.out.println("IfTestImpl初始化...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    2 被动引用

    除了上述主动引用的六种情况会触发类的初始化,其他的引用都不会触发初始化,被称为被动引用,以下是被动引用的其中几种情况举例:

    1. 通过子类的引用父类的静态属性,不会导致子类初始化。
    2. 通过定义数组引用类,不会导致该类初始化。
    3. 访问类中final修饰的静态变量(常量在编译期间会存入常量池,本质上并没有直接引用到定义该常量的类,所以不会触发该类的初始化)。
    public class ClassInitTest2 {
        public static void main(String[] args) {
            System.out.println(SubClass.m);
        }
    }
    
    /**
     * 被动使用类字段
     * 通过子类引用父类的静态字段,不会导致子类的初始化
     */
    class SuperClass{
        static {
            System.out.println("Super class init");
        }
    
        public final static int m = 20;
        public static int n = 10;
    }
    
    class SubClass extends SuperClass{
        static {
            System.out.println("SubClass init");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    image-20231114233108100

    image-20231114233152695

  • 相关阅读:
    编译ncurses-5.9出错
    QT简介、安装与运行
    java-net-php-python-jspm校园闲置物品拍卖系统计算机毕业设计程序
    Centos IPTABLES
    漫谈AI 时代的信息模型
    责任链设计模式
    【问道】编译原理
    vulnhub靶场之PYLINGTON: 1
    Gitee和Git学习笔记
    让AI玩《我的世界》
  • 原文地址:https://blog.csdn.net/qq_40493944/article/details/134410366