• JVM中java类的加载时机(转载:http://blog.csdn.net/chenleixing/article/details/47099725)


    Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的加载机制。
    类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括了:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(using)、和卸载(Unloading)七个阶段。其中验证、准备和解析三个部分统称为连接(Linking),如下如所示。


    这七个阶段,加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,类的加载过程必须按照这个顺序来按部就班地开始,而解析阶段则不一定,它在某些情况下可以在初始化阶段后再开始。

    类的生命周期的每一个阶段通常都是互相交叉混合式进行的,通常会在一个阶段执行的过程中调用或激活另外一个阶段。
    Java虚拟机规范没有强制性约束在什么时候开始类加载过程,但是对于初始化阶段,虚拟机规范则严格规定了有且只有四种情况必需立即对类进行“初始化”(而加载、验证、准备阶段则必需在此之前开始),这四种情况归类如下:

    1.遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令最常见的Java代码场景是:使用new关键字实例化对象时、读取或者设置一个类的静态字段(被final修饰、已在编译器把结果放入常量池的静态字段除外)时、以及调用一个类的静态方法的时候。
    2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
    3.当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要触发父类的初始化。
    4.当虚拟机启动时,用户需要指定一个执行的主类(包含main()方法的类),虚拟机会先初始化这个类。
    对于这四种触发类进行初始化的场景,在java虚拟机规范中限定了“有且只有”这四种场景会触发。这四种场景的行为称为对类的主动引用,除此以外的所有引用类的方式都不会触发类的初始化,称为被动引用。

    下面通过三个实例来说明被动引用:

    示例1:


     
    1. 父类SuperClass.java   
    2. public class SuperClass {    
    3.     static{    
    4.          System.out.println("SuperClass init!");    
    5.       }    
    6.      public static int value = 123;    
    7. }    
    8. 子类SubClass.java  
    9.      public class SubClass extends SuperClass {    
    10.      static{    
    11.         System.out.println("SubClass init!");    
    12.     }    
    13. }    
    14.    
    15. 主类NotInitialization.java  
    16. public class NotInitialization {    
    17.     public static void main(String[] args) {    
    18.         System.out.println(SubClass.value);    
    19.     }    
    20. }    

     
    1. 输出结果:  
    2.   
    3. SuperClass init!   
    4.   
    5. 123    


    由结果可以看出只输出了“SuperClass init!”,没有输出“SubClass init!”。这是因为对于静态字段,只有直接定义该字段的类才会被初始化,因此当我们通过子类来引用父类中定义的静态字段时,只会触发父类的初始化,而不会触发子类的初始化。

    示例2:


     
    1. SuperClass[ ]   scs=new SuperClass[11];  


    如上,当初始化一个对象数组的时候,也不会触发类的初始化。

    示例3:


     
    1. public class ConstClass {  
    2.   
    3.    static {  
    4.   
    5.     system.out.printl("const");  
    6.   
    7. }  
    8.   
    9.    public static final int age =123;    
    10.   
    11. }  
    12.   
    13. public class NotInitialization{  
    14.   
    15.      public static void main(String[ ] args){  
    16.   
    17.      system.out.println(ConstClass.age);  
    18.   
    19. }  

    此时并不会出现 “const”,因为在NotInitialization类在编译的时候已经把ConstClass中的变量age放在常量池中了,访问时直接取出age即可,不会引发ConstClass的初始化。

  • 相关阅读:
    Elasticsearch 搜索的评分机制
    Elasticsearch-mapper 基于注解方式生成mapping(2.0以上)
    Elasticsearch 与 Mongodb 数据同步问题
    Hadoop入门进阶课程6--MapReduce应用案例
    Hadoop入门进阶课程5--MapReduce原理及操作
    Hadoop入门进阶课程4--HDFS原理及操作
    Hadoop入门进阶课程3--Hadoop2.X64位环境搭建
    使用命令行备份指定文件夹并保留最新N份
    Hadoop入门进阶课程2--Hadoop2.X 64位编译
    Hadoop入门进阶课程1--Hadoop1.X伪分布式安装
  • 原文地址:https://www.cnblogs.com/caobojia/p/6011170.html
Copyright © 2020-2023  润新知