03 | Java虚拟机是如何加载Java类的?
该思维导图由 AI 生成,仅供参考
- 深入了解
- 翻译
- 解释
- 总结
Java虚拟机加载Java类的过程类似于盖房子,需要经历加载、链接和初始化三大步骤。加载阶段通过类加载器查找字节流并创建类,类加载器按照双亲委派模型依次转发加载请求。链接阶段包括验证、准备和解析,确保类满足虚拟机约束条件并为静态字段分配内存。解析阶段将符号引用解析为实际引用,触发未加载类的加载。文章还介绍了Java类的分类和不同类加载器的职责,以及Java 9对类加载器的略微更改。总的来说,文章详细解释了Java虚拟机加载类的过程和相关概念,为读者深入理解Java类加载提供了全面的指导。 在Java代码中,静态字段的初始化可以通过直接赋值或静态代码块实现。类加载的最后一步是初始化,确保常量值字段被赋值,并执行< clinit >方法。类的初始化触发情况包括虚拟机启动、new指令、静态方法调用等。文章还提供了一个单例延迟初始化例子,说明了类初始化的线程安全特性。 总结来说,文章详细介绍了Java虚拟机将字节流转化为Java类的过程,包括加载、链接和初始化三大步骤。加载通过类加载器查找字节流并创建类,链接阶段确保类满足虚拟机约束条件,初始化阶段为常量值字段赋值并执行< clinit >方法。读者可以通过实践验证理论知识,例如使用JVM参数-verbose:class打印类加载顺序。整体而言,本文为读者提供了深入理解Java类加载的全面指南。
《深入拆解 Java 虚拟机》,新⼈⾸单¥59
全部留言(163)
- 最新
- 精选
- 笨鸟1.虚拟机必须知道(加载)有这个类,才能创建这个类的数组(容器),但是这个类并没有被使用到(没有达到初始化的条件),所以不会初始化。 2.新建数组的时候并不是要使用这个类(只是定义了放这个类的容器),所以不会被链接,调用getInstance(false)的时候约等于告诉虚拟机,我要使用这个类了,你把这个类造好(链接),然后把static修饰的字符赋予变量(初始化)。 老师看看理解对不对,指点一下。
作者回复: 对的!
2018-10-185112 - 曲东方1. 新建数组会加载元素类LazyHolder;不会初始化元素类 2. 新建数组不会链接元素类LazyHolder;在getInstance(false)时才真正链接和初始化 ----------------- 链接的第一步:验证字节码,awk把字节码改为不符合jvm规范 初始化调用<clinit>(即class init) PS:好像二个问题包含了第一个问题的答案
作者回复: 多谢指出!
2018-07-25495 - mover到目前为止,讲解的内容没有超出周志明老师的 深入理解JAVA虚拟机这本书的内容,老师可以讲解的更深入一点吗?可以介绍一下类加载后在meta区的大概布局吗?class类对象与meta区的类数据结构是什么关系?当我们创建类,使用类时,类实例,类对象,meta区类数据结构是如何交互的?
作者回复: 谢谢你的建议!前几章不好搞太难,希望后面能够满足你的需求
2018-07-25246 - 韩恩同忍着瞌睡把内容看完了。 全是复习了一遍。 作者对 类加载中的 链接(验证、准备、解析)讲解不太到位吧? 另外,对一个的初始化发生在第一次主动使用该类时,作者列出的几种情况都属于主动使用类。感觉应该有被动使用的举例,并告知大家这样做是不会执行初始化的。
作者回复: 多谢建议!
2018-07-27330 - conce2018为什么叫双亲委派呀,明明只给了父类加载应该是单亲呀
作者回复: 其实我也有这个疑问,英文中为parent不带s,照理应该翻译为单亲。但既然约定俗成翻译为双亲,就只好这样叫啦
2018-09-25727 - 熊猫酒仙有几个疑问,请老师指点迷津。 1.扩展类加载器的父类,是启动类加载器,而后者是C++实现的,java继承C++的类?不大能理解。 2.虚方法的概念在C++中有了解过,java中的虚方法该如何定义呢?以前没接触过java虚方法的概念 3.我以前的理解是,有一个零值(0/null)初始化,针对于类的静态成员变量,如果是final修饰的静态成员变量,也就是常量,是初始化为代码中指定的值比如10。非final修饰的静态成员变量,在clint执行过程中赋值为代码中指定的值,请问老师是这样的吗?
作者回复: 1. 可能我翻译得有点瑕疵,导致了你的误解。这里我指的是扩展器类的 父-类加载器,而不是父类-(加载器)。 2. Java中所有的非私有实例方法,都算是虚方法。调用这些方法的指令,也区分直接调用和虚调用。下一篇我会讲到。 3. 赞一个。被final修饰的静态成员变量,如果不是基本类型或者字符串,也会放在clinit 来做。
2018-07-25520 - Skysper每次new一个类都是一次初始化吧?加载和链接以后生成的是什么样的数据结构?存储在什么地方?
作者回复: 类的初始化只会发生一次,你可能指的是实例的初始化? JVM并不会直接使用.class文件,类加载链接的目的就是在JVM中创建相应的类结构,会存储在元空间(我之前用的老说法”方法区”,感谢某同学指出)。
2018-07-25518 - Super丶X老师,你说可以通过不同的类加载器加载同一个类得到类的不同版本,我有个疑问,类是通过包名加类名来使用的,那怎么样区分不同的类加载器加载的类呢?
作者回复: 你指的是在写代码的时候如何区分对吧?我认为没法区分。如果你有一个类的两个不同版本,而且它们不兼容,那么编译时指向哪个,就按哪个来编译。也就是说,如果要同时使用两个版本,那么你需要分开编译。
2018-07-25213 - 小蛋壳加载阶段都加载哪些类呢,那么多类,全部加载吗?
作者回复: 加载阶段是针对单个类的,一般用到的类才会被加载。大部分情况下,不同类的加载阶段是不同的。
2018-07-269 - L.B.Q.Y从大的方面讲,类加载的结果是把一段字节流变换成Class结构并写方法区,实际写方法区具体是发生在加载、链接、初始化的哪个环节呢?
作者回复: 在加载阶段就已经生成class结构了,所以我认为应该已经写入了方法区,只是被标记为未链接而暂不能使用。
2018-07-2538