• 虚拟机类加载机制之类的初始化时机


    引言

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

    类的生命周期

      

    类初始化的时机

      第一个阶段加载是由虚拟机控制,对于初始化阶段,虚拟机严格要求有且只有5种情况触发初始化。

      1)遇到new、putstatic、getstatic、invokestatic指令时触发,也就是使用new关键字实例化对象时、读取和设置类的静态字段(被final static修饰存入常量池的除外)、调用类的静态方法。

      2)使用java.lang.reflect包的方法对类进行反射调用时触发。

      3)初始化一个类时发现其父类未初始化时会初始化其父类。

      4)虚拟机启动时,用户需指定一个主类(含有main方法的类),首先初始化该主类。

      5)使用jdk1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果是REF_getstatic、REF_petstatic、REF_invokestatic的方法句柄,并且该方法句柄对应的类没有初始化时触发。

      上述五种情况属于主动引用,还有被动引用不会触发初始化。

      被动引用案例1

    package com.wjz.demo;
    public class SuperClass {
        public static int i = 1;
        static {
            System.out.println("SuperClass init");
        }
    }
    package com.wjz.demo;
    public class SubClass extends SuperClass {
        static {
            System.out.println("SubClass init");
        }
    }
    package com.wjz.demo;
    public class NotInitialization {
        /**
         * 非主动使用类字段
         */
        public static void main(String[] args) {
            System.out.println(SubClass.i);
        }
    }

    输出结果

    SuperClass init
    1

      对于静态字段只有直接定义该字段的类会被初始化,通过子类引用父类的静态字段只会初始化父类。

      被动引用案例2

    package com.wjz.demo;
    public class NotInitialization {
        /**
         * 通过数组定义来引用类,不会初始化该类
         */
        public static void main(String[] args) {
            SuperClass[] scs = new SuperClass[10];
        }
    }

      运行结果是什么都没有,说明没有初始化SuperClass类,但是虚拟机触发了另外一个名为“[Lcom.wjz.demo.SuperClass”的类的初始化阶段,这是由虚拟机自动生成的,创建动作由newarray指令触发。

      被动引用案例3

    package com.wjz.demo;
    public class ConstantClass {
        public final static String val = "Hello";
        static {
            System.out.println("ConstantClass init");
        }
    }
    package com.wjz.demo;
    public class NotInitialization {
        /**
         * 常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,不会初始化定义常量的类
         */
        public static void main(String[] args) {
            System.out.println(ConstantClass.val);
        }
    }

      运行结果只输出了“Hello”,这是因为在编译阶段通过常量传播优化,“Hello”存储到了NotInitialization类的常量池中,之后对常量ConstantClass.val的引用实际都转化为了NotInitialization对自身常量池的引用,NotInitialization的Class文件中没有ConstantClass类的符号引用入口。  

  • 相关阅读:
    图片展示,带分页
    miniui动态合并datagrid列
    使用webcam和video插件/华为云播放插件,实现视频播放及拍照上传功能
    Java实现excel导出(内容循环多个)
    C# 图片与Base64互转
    C#中将字符串转成 Base64 编码 (加密--解密)
    ASP.NET导出Excel之二
    利用Aspose转PDF
    ASP.NET视频播放
    Oracle存储过程导入,判断已有数据更新,没有的数据导入,统计导入成功与失败数,返回一个表
  • 原文地址:https://www.cnblogs.com/BINGJJFLY/p/7678039.html
Copyright © 2020-2023  润新知