zoukankan      html  css  js  c++  java
  • 虚拟机类加载机制之类的初始化时机

    引言

      虚拟机把描述类的数据即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类的符号引用入口。  

  • 相关阅读:
    Bat脚本处理ftp超强案例解说
    struts2中的输入校验
    struts国际化
    Spring2.5+Hibernate3.3的集成
    SQL Server如果视图存在就删除
    struts2自定义拦截器
    struts2标签
    spring2.5的第一个简单应用的学习
    基于XML配置方式实现对action的所有方法进行校验
    DataGridViewCell 类
  • 原文地址:https://www.cnblogs.com/BINGJJFLY/p/7678039.html
Copyright © 2011-2022 走看看