类加载过程中每个步骤的顺序

我们已经知道,类加载的过程包括:加载、连接、初始化,连接又分为:验证、准备、解析,所以说类加载一共分为5步:加载、验证、准备、解析、初始化。

其中加载、验证、准备、初始化的开始顺序是依次进行的,这些步骤开始之后的过程可能会有重叠。 
而解析过程会发生在初始化过程中。

类加载过程中“初始化”开始的时机

JVM规范中只定义了类加载过程中初始化过程开始的时机,加载、连接过程都应该在初始化之前开始(解析除外),这些过程具体在何时开始,JVM规范并没有定义,不同的虚拟机可以根据具体的需求自定义。

初始化开始的时机:

  • 在运行过程中遇到如下字节码指令时,如果类尚未初始化,那就要进行初始化:new、getstatic、putstatic、invokestatic。这四个指令对应的Java代码场景是:

    •   通过new创建对象;
    •   读取、设置一个类的静态成员变量(不包括final修饰的静态变量);
    •   调用一个类的静态成员函数。
  • 使用java.lang.reflect进行反射调用的时候,如果类没有初始化,那就需要初始化;
  • 当初始化一个类的时候,若其父类尚未初始化,那就先要让其父类初始化,然后再初始化本类;
  • 当虚拟机启动时,虚拟机会首先初始化带有main方法的类,即主类;

主动引用 与 被动引用

JVM规范中要求在程序运行过程中,“当且仅当”出现上述4个条件之一的情况才会初始化一个类。如果间接满足上述初始化条件是不会初始化类的。 
其中,直接满足上述初始化条件的情况叫做主动引用;间接满足上述初始化过程的情况叫做被动引用。 
那么,只有当程序在运行过程中满足主动引用的时候才会初始化一个类,若满足被动引用就不会初始化一个类。

接口的初始化

接口和类都需要初始化,接口和类的初始化过程基本一样,不同点在于:类初始化时,如果发现父类尚未被初始化,则先要初始化父类,然后再初始化自己;但接口初始化时,并不要求父接口已经全部初始化,只有程序在运行过程中用到当父接口中的东西时才初始化父接口(没用到父接口的变量或者方法时不需要初始化父接口)。

例子

被动引用的场景示例

public class Fu{
public static String name = "test";
static{
System.out.println("父类被初始化!");
}
}
public class Zi{
static{
System.out.println("子类被初始化!");
}
}
public static void main(String[] args){
System.out.println(Zi.name);
}
输出结果:
父类被初始化!
test
原因分析:
本示例看似满足初始化时机的第一条:当要获取某一个类的静态成员变量的时候如果该类尚未初始化,则对该类进行初始化。
但由于这个静态成员变量属于Fu类,Zi类只是间接调用Fu类中的静态成员变量,因此Zi类调用name属性属于间接引用,
而Fu类调用name属性属于直接引用,由于JVM只初始化直接引用的类,因此只有Fu类被初始化。
public class A{
public static void main(String[] args){
Fu[] arr = new Fu[10];
}
}
输出结果:
并没有输出“父类被初始化!”
原因分析:
这个过程看似满足初始化时机的第一条:遇到new创建对象时若类没被初始化,则初始化该类。
但现在通过new要创建的是一个数组对象,而非Fu类对象,因此也属于间接引用,不会初始化Fu类。
public class Fu{
public static final String name = "test";
static{
System.out.println("父类被初始化!");
}
}
public class A{
public static void main(String[] args){
System.out.println(Fu.name);
}
}
输出结果:
test
原因分析:
本示例看似满足类初始化时机的第一个条件:获取一个类静态成员变量的时候若类尚未初始化则初始化类。
但是,Fu类的静态成员变量被final修饰,它已经是一个常量。
被final修饰的常量在Java代码编译的过程中就会被放入它被引用的class文件的常量池中(这里是A的常量池)。
所以程序在运行期间如果需要调用这个常量,直接去当前类的常量池中取,而不需要初始化这个类。

JVM的类加载时机的更多相关文章

  1. 【JVM】类加载时机与过程

    虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制.下面来总结梳理类加载的五个阶段. 类加载发生在 ...

  2. 从一道面试题来认识java类加载时机与过程

    说明:本文的内容是看了<深入理解Java虚拟机:JVM高级特性与最佳实践>后为加印象和理解,便记录了重要的内容. 1  开门见山 以前曾经看到过一个java的面试题,当时觉得此题很简单,可 ...

  3. java类加载时机与过程

    转自:http://www.tuicool.com/articles/QZnENv 说明:本文的内容是看了<深入理解Java虚拟机:JVM高级特性与最佳实践>后为加印象和理解,便记录了重要 ...

  4. 深入理解JVM(3)——类加载机制

    1.类加载时机 类的整个生命周期包括了:加载( Loading ).验证( Verification ).准备( Preparation ).解析( Resolution ).初始化( Initial ...

  5. 从一道面试题来认识java类加载时机与过程【转】

    说明:本文的内容是看了<深入理解Java虚拟机:JVM高级特性与最佳实践>后为加印象和理解,便记录了重要的内容. 1  开门见山 以前曾经看到过一个java的面试题,当时觉得此题很简单,可 ...

  6. JVM自定义类加载器加载指定classPath下的所有class及jar

    一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责 ...

  7. 漫谈JVM之类加载机制(篇一)

    前言 最近在看一本书,发现代码里用到了Thread.currentThread().getContextClassLoader(),为什么类加载器还与线程有关系呢,为什么不直接使用ClassLoade ...

  8. 深入理解JVM之类加载

    ---title: [学习]深入理解JVM之类加载.mddate: 2019-10-20 22:20:06tags: JVM 类加载--- Java类的加载,连接,初始化都是在程序运行期间执行的 ## ...

  9. JVM:类加载与字节码技术-2

    JVM:类加载与字节码技术-2 说明:这是看了 bilibili 上 黑马程序员 的课程 JVM完整教程 后做的笔记 内容 这部分内容在上一篇笔记中: 类文件结构 字节码指令 编译期处理 类加载阶段 ...

随机推荐

  1. MVC v5.1 Preview 包含 web api 2.1 web pages 3.1

    Includes ASP.NET MVC 5.1, Web API 2.1, and Web Pages 3.1 preview release. This was released marked a ...

  2. solr特点二:Facet

    返回查询集合中指定field的统计情况,例如找到city一样的文档数目: 加入文档 <add> <doc> <field name="id">1 ...

  3. 异步和等待(async和await)

    在.Net 4.5中,通过async和await两个关键字,引入了一种新的基于任务的异步编程模型(TAP).在这种方式下,可以通过类似同步方式编写异步代码,极大简化了异步编程模型.如下式一个简单的实例 ...

  4. Polynomial ( Arithmetic and Algebra) CGAL 4.13 -User Manual

    1 Fundamentals A polynomial is either zero, or can be written as the sum of one or more non-zero ter ...

  5. MongoDB账号管理及实践

    此文已由作者温正湖授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 目前蜂巢(云计算基础服务)MongoDB上已经有数十个实例,其中不少是企业用户或公司内部产品用户的.用户多了 ...

  6. 「SDOI2008」洞穴勘测

    题目链接 戳我 \(Solution\) \(LCT\)裸题 \(Connect\)操作,执行\(link(u,v)\) \(Destroy\)操作,执行\(cut(u,v)\) \(Query\)操 ...

  7. Vue的基本认识与使用

    什么是Vue? Vue是一个渐进式的js框架,采用的是MVVM模式的双向绑定, Vue的使用 引入vue        <script src="vuejs/vue.js"& ...

  8. GO学习笔记 - 没有参数的 return 语句返回各个返回变量的当前值,这种用法被称作“裸”返回。

    Go 的返回值可以被命名,并且就像在函数体开头声明的变量那样使用. 返回值的名称应当具有一定的意义,可以作为文档使用. 没有参数的 return 语句返回各个返回变量的当前值.这种用法被称作“裸”返回 ...

  9. iterrows() 函数对dataframe进行遍历

    for循环遍历dataframe,返回有一个元祖类型,第一个是行的索引,第二个是series,是每一行的内容.

  10. jQuery中animate与scrollTop、offset().top实例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...