`

JVM学习笔记(六):类加载的时机

    博客分类:
  • JVM
 
阅读更多

本文根据《深入理解java虚拟机》第7章部分内容整理

 

    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虚拟机规范中限定了“有且只有”这四种场景会触发。这四种场景的行为称为对类的主动引用,除此以外的所有引用类的方式都不会触发类的初始化,称为被动引用。

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

示例一

父类SuperClass.java

 

Java代码  收藏代码
  1. package com.chenzhou.classloading;  
  2. /** 
  3.  * ClassName:SuperClass <br/> 
  4.  * Function: 被动使用类:通过子类引用父类的静态字段,不会导致子类初始化. <br/> 
  5.  * Date:     2012-7-18 上午09:37:06 <br/> 
  6.  * @author   chenzhou 
  7.  * @version   
  8.  * @since    JDK 1.6 
  9.  * @see       
  10.  */  
  11. public class SuperClass {  
  12.     static{  
  13.         System.out.println("SuperClass init!");  
  14.     }  
  15.     public static int value = 123;  
  16. }  

子类SubClass.java

Java代码  收藏代码
  1. package com.chenzhou.classloading;  
  2.   
  3. public class SubClass extends SuperClass {  
  4.     static{  
  5.         System.out.println("SubClass init!");  
  6.     }  
  7. }  

主类NotInitialization.java

Java代码  收藏代码
  1. package com.chenzhou.classloading;  
  2. /** 
  3.  * ClassName:NotInitialization <br/> 
  4.  * Function: 非主动使用类字段演示. <br/> 
  5.  * Date:     2012-7-18 上午09:41:14 <br/> 
  6.  * @author   chenzhou 
  7.  * @version   
  8.  * @since    JDK 1.6 
  9.  * @see       
  10.  */  
  11. public class NotInitialization {  
  12.     public static void main(String[] args) {  
  13.         System.out.println(SubClass.value);  
  14.     }  
  15. }  

 输出结果:

Txt代码  收藏代码
  1. SuperClass init!  
  2. 123  

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

 

 

示例二

父类SuperClass.java如上一个示例一样

主类NotInitialization.java

 

Java代码  收藏代码
  1. package com.chenzhou.classloading;  
  2. /** 
  3.  * ClassName:NotInitialization <br/> 
  4.  * Function: 通过数组定义来引用类,不会触发此类的初始化. <br/> 
  5.  * Date:     2012-7-18 上午09:41:14 <br/> 
  6.  * @author   chenzhou 
  7.  * @version   
  8.  * @since    JDK 1.6 
  9.  * @see       
  10.  */  
  11. public class NotInitialization {  
  12.     public static void main(String[] args) {  
  13.         SuperClass[] scs = new SuperClass[10];  
  14.     }  
  15. }  

输出结果为空

   没有输出“SuperClass init!”说明没有触发类com.chenzhou.classloading.SuperClass的初始化阶段,但是这段代码会触发“[Lcom.chenzhou.classloading.SuperClass”类的初始化阶段(有个L是数组对象)。这个类是由虚拟机自动生成的,该创建动作由newarray触发。

 

示例三

常量类ConstClass.java

 

Java代码  收藏代码
  1. package com.chenzhou.classloading;  
  2. /** 
  3.  * ClassName:ConstClass <br/> 
  4.  * Function: 常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化. <br/> 
  5.  * Reason:   TODO ADD REASON. <br/> 
  6.  * Date:     2012-7-18 上午09:46:56 <br/> 
  7.  * @author   chenzhou 
  8.  * @version   
  9.  * @since    JDK 1.6 
  10.  * @see       
  11.  */  
  12. public class ConstClass {  
  13.     static{  
  14.         System.out.println("ConstClass init!");  
  15.     }  
  16.       
  17.     public static final String HELLOWORLD = "hello world";  
  18. }  

主类NotInitialization.java

Java代码  收藏代码
  1. package com.chenzhou.classloading;  
  2. /** 
  3.  * ClassName:NotInitialization <br/> 
  4.  * Function: 非主动实用类字段演示. <br/> 
  5.  * Date:     2012-7-18 上午09:41:14 <br/> 
  6.  * @author   chenzhou 
  7.  * @version   
  8.  * @since    JDK 1.6 
  9.  * @see       
  10.  */  
  11. public class NotInitialization {  
  12.     public static void main(String[] args) {  
  13.         System.out.println(ConstClass.HELLOWORLD);  
  14.     }  
  15. }  

输出:hello world

    上面的示例代码运行后也没有输出“SuperClass init!”,这是因为虽然在Java源码中引用了ConstClass类中的常量HELLOWORLD,但是在编译阶段将此常量的值“hello world”存储到了NotInitialization类的常量池中,对于常量ConstClass.HELLOWORLD的引用实际上都被转化为NotInitialization类对自身常量池的引用了。实际上NotInitialization的Class文件之中已经不存在ConstClass类的符号引用入口了。

   接口的加载过程与类加载的区别在于上面提到的四种场景中的第三种,当类在初始化时要求其父类都已经初始化过了,但是一个接口在初始化时,并不要求其父类都完成了初始化,只有在真正用到父类接口的时候(如引用父接口的常量)才会初始化

分享到:
评论

相关推荐

    JVM(三):类加载机制(类加载过程和类加载器)1

    Java虚拟机(JVM)的类加载机制是Java应用程序运行灵活性的关键。类加载涉及多个步骤,包括加载、验证、准备、解析、初始化、使用和卸载。这些阶段确保了类的正确加载、验证其安全性和有效运行。 1. **加载...

    JVM学习笔记(一)

    ### JVM学习笔记(一) #### 一、JVM概述与工具使用 JVM(Java Virtual Machine)是Java语言的核心组成部分之一,它为Java程序提供了一个跨平台的运行环境。本篇学习笔记主要介绍如何利用一系列工具来查看和监控JVM...

    java之jvm学习笔记五(实践写自己的类装载器)

    这个“java之jvm学习笔记五(实践写自己的类装载器)”很可能是对这一主题的详细探讨。 类装载器在Java中的主要职责是动态加载类到JVM中。Java的类装载器分为三个基本层次:启动类装载器(Bootstrap ClassLoader)、...

    JVM:类加载器子系统.pdf

    Java虚拟机(JVM)的类加载器子系统是Java运行时环境的一个重要组成部分,它负责将.class文件加载到内存中,并生成对应的Java类对象。这一过程涵盖了从文件系统或网络获取.class文件、验证类文件的正确性、准备类...

    JVM实战-JVM类加载机制案例分析

    2. **类加载器及类加载器的委托机制**:JVM中有三种内置的类加载器,分别是启动类加载器、扩展类加载器和应用类加载器。此外,还可以自定义类加载器。类加载器之间遵循委托机制,即下级类加载器先请求上级类加载器...

    JVM学习笔记

    ### JVM学习笔记 #### JVM内存模型 (JMM) JVM内存模型主要分为以下几个部分: - **Java堆**:这是所有线程共享的一块区域,在虚拟机启动时创建。主要用于存放对象实例,几乎所有的对象实例都在这里分配内存。 - *...

    JVM学习笔记.docx

    本篇JVM学习笔记主要涵盖了以下几个核心知识点: 1. **运行时数据区**: - **程序计数器**:记录当前线程执行的字节码的行号,用于线程恢复执行时跳转到正确位置。 - **Java虚拟机栈**:每个方法执行时创建的栈帧...

    jvm视频及笔记

    "jvm视频及笔记"这个资源显然是一份全面学习JVM的材料,结合了视频教程和书面笔记,帮助学习者深入理解JVM的工作原理及其在实际开发中的应用。 JVM的学习可以从以下几个重要的知识点开始: 1. **JVM架构**:JVM...

    jvm学习笔记(jvm内存模型&垃圾收集算法&类加载机制)

    在JVM的学习中,理解其内存模型、垃圾收集算法以及类加载机制至关重要。 1. **JVM内存模型** - **方法区**:也称为“永久代”,存储虚拟机加载的类信息、常量、静态变量等,是线程共享的区域。在Java 8之后,这...

    JVM 学习笔记(Java虚拟机)

    本笔记将从以下几个方面详细介绍JVM: 1. **JVM架构** - 类加载子系统:负责加载、验证、准备、解析和初始化类。 - 运行时数据区:包括程序计数器、虚拟机栈、本地方法栈、堆和方法区。 - 执行引擎:负责执行...

    java之jvm学习笔记十一(访问控制器)-源码

    本文将深入探讨JVM中的访问控制器,主要基于“java之jvm学习笔记十一(访问控制器)-源码”这一主题,以及相关的源码分析。 首先,我们得了解Java的安全模型。Java安全模型基于一种称为安全管理器(SecurityManager)...

    深入Java虚拟机JVM类加载学习笔记

    ### 深入Java虚拟机JVM类加载学习笔记 #### 一、Classloader机制解析 在Java虚拟机(JVM)中,类加载器(ClassLoader)是负责将类的`.class`文件加载到内存中的重要组件。理解类加载器的工作原理对于深入掌握JVM以及...

    Java虚拟机JVM类加载学习笔记

    Java虚拟机(JVM)是Java程序的核心组成部分,它负责执行字节码并...理解JVM的类加载机制对于优化程序性能、解决类加载问题以及深入学习Java运行机制至关重要。开发者应当掌握这些概念,以便更好地编写和调试Java代码。

    JVM类加载机制详细讲解

    例如,当我们尝试加载 `java.lang.Object` 类时,首先会由启动类加载器加载,如果它找不到,会继续交给扩展类加载器,接着是系统类加载器,最后才会由用户自定义的类加载器尝试加载。 1.3 类加载双亲委派示例 为了...

    JVM学习资料+笔记

    这个资料包不仅涵盖了理论知识,还包含个人的学习笔记,对于学习和掌握JVM的各个方面都将大有裨益。无论是初学者还是经验丰富的开发者,都可以从中找到提升自己技能的宝贵资源。通过深入学习和实践,可以更好地理解...

    jVM学习笔记.ppt

    Java虚拟机(JVM)是Java平台的核心组成部分,它负责运行Java程序,并提供了内存管理、垃圾回收以及类加载等关键功能。JVM的学习可以从其基本结构、代码编译和执行过程,以及内存管理和垃圾回收机制三个方面进行深入...

    JVM、Tomcat、OSGI等类加载器整理文档

    在Java世界中,类加载器(ClassLoader)是关键组件,它们负责将类的字节码加载到Java虚拟机(JVM)中。JVM、OSGI(Open Service Gateway Initiative)和Tomcat等容器都涉及到了类加载器的概念,理解它们的工作原理对...

    JVM类加载过程.pptx

    JVM类加载过程 JVM(Java Virtual Machine)是Java语言的核心组件之一,它是Java语言的可移植性和跨平台性的基础。JVM主要组成部分包括类加载子系统、执行引擎、本地方法接口和运行时数据区。 类加载子系统是JVM的...

    JVM面试资料:JVM结构、JVM调优、四大垃圾回收算法、七大垃圾回收器

    JVM结构:类加载器,执行引擎,本地方法接口,本地内存结构; 四大垃圾回收算法:复制算法、标记-清除算法、标记-整理算法、分代收集算法 七大垃圾回收器:Serial、Serial Old、ParNew、CMS、Parallel、Parallel Old...

    马士兵jvm调优笔记.docx

    ### 马士兵JVM调优笔记知识点梳理 #### 一、Java内存结构 Java程序运行时,其内存被划分为几个不同的区域,包括堆内存(Heap)、方法区(Method Area)、栈(Stack)、程序计数器(Program Counter Register)以及...

Global site tag (gtag.js) - Google Analytics