03 | Java虚拟机是如何加载Java类的?
03 | Java虚拟机是如何加载Java类的?
讲述:郑雨迪
时长12:39大小5.80M
加载
链接
初始化
总结与实践
赞 29
提建议
精选留言(162)
- 笨鸟2018-10-181.虚拟机必须知道(加载)有这个类,才能创建这个类的数组(容器),但是这个类并没有被使用到(没有达到初始化的条件),所以不会初始化。 2.新建数组的时候并不是要使用这个类(只是定义了放这个类的容器),所以不会被链接,调用getInstance(false)的时候约等于告诉虚拟机,我要使用这个类了,你把这个类造好(链接),然后把static修饰的字符赋予变量(初始化)。 老师看看理解对不对,指点一下。展开
作者回复: 对的!
共 4 条评论105 - 曲东方2018-07-251. 新建数组会加载元素类LazyHolder;不会初始化元素类 2. 新建数组不会链接元素类LazyHolder;在getInstance(false)时才真正链接和初始化 ----------------- 链接的第一步:验证字节码,awk把字节码改为不符合jvm规范 初始化调用<clinit>(即class init) PS:好像二个问题包含了第一个问题的答案展开
作者回复: 多谢指出!
共 4 条评论94 - 迈克擂2018-07-29学习了!可以的话希望老师能附上一些图解,便于更理解87
- akka2018-07-27-XX:+TraceClassLoading 可以看到类加载过程52
- mover2018-07-25到目前为止,讲解的内容没有超出周志明老师的 深入理解JAVA虚拟机这本书的内容,老师可以讲解的更深入一点吗?可以介绍一下类加载后在meta区的大概布局吗?class类对象与meta区的类数据结构是什么关系?当我们创建类,使用类时,类实例,类对象,meta区类数据结构是如何交互的?
作者回复: 谢谢你的建议!前几章不好搞太难,希望后面能够满足你的需求
共 2 条评论46 - 佑儿2019-05-16总结: jvm加载java类就是将字节流(如.class文件,网络传输的字节流)文件加入到内存中的过程,分为以下三步:加载、链接、初始化 加载:查找字节流并且据此创建类的过程,每一种类加载器加载一部分类 加载规则:双亲委派机制 类的唯一性:类加载器名称+类全限定名称 类加载器: 启动类加载器:无对应的java对象,负责加载最基础的类。如jre/lib下的类以及有虚拟机参数-Xbootclasspath指定的类, 扩展类加载器:有对应的java对象,父类启动类加载器,负责加载jre/ext下类以及系统变量java.ext.dirs指定的类 该类加载器被启动类加载器加载之后方能加载其他类, 应用类加载器:有对应的java对象,父类是扩展类加载器,负责加载应用程序路径下的类/classpath、系统变量java.class.path或者环境变量classpath指定的类。 链接:验证、准备、解析 验证:在于确定被加载类满足jvm的约束条件。 准备:为被加载类的静态字段分配内存。 解析:将符号引用解析为实际引用, 符号引用是在编译阶段由编译器生成,包含目标方法所在类的名字、目标方法的名字、接收参数类型以及返回值类型 初始化:为标记为常量值的字段(基本类型或字符串且被修饰为final)赋值,以及执行<clinit>方法(其他赋值操作和静态代码块) 类的初始化过程是线程安全的,并且只能被初始化一次。jvm会通过加锁来保证<clinit>方法仅被执行一次 初始化的时机(对一个类的主动引用) 被动引用并不会引发类的初始化,如引用类的静态常量,引用父类的静态字段不会初始化子类,数组定义来引用类不会导致初始化。展开共 4 条评论37
- 韩恩同2018-07-27忍着瞌睡把内容看完了。 全是复习了一遍。 作者对 类加载中的 链接(验证、准备、解析)讲解不太到位吧? 另外,对一个的初始化发生在第一次主动使用该类时,作者列出的几种情况都属于主动使用类。感觉应该有被动使用的举例,并告知大家这样做是不会执行初始化的。
作者回复: 多谢建议!
共 3 条评论27 - conce20182018-09-25为什么叫双亲委派呀,明明只给了父类加载应该是单亲呀
作者回复: 其实我也有这个疑问,英文中为parent不带s,照理应该翻译为单亲。但既然约定俗成翻译为双亲,就只好这样叫啦
共 6 条评论26 - 熊猫酒仙2018-07-25有几个疑问,请老师指点迷津。 1.扩展类加载器的父类,是启动类加载器,而后者是C++实现的,java继承C++的类?不大能理解。 2.虚方法的概念在C++中有了解过,java中的虚方法该如何定义呢?以前没接触过java虚方法的概念 3.我以前的理解是,有一个零值(0/null)初始化,针对于类的静态成员变量,如果是final修饰的静态成员变量,也就是常量,是初始化为代码中指定的值比如10。非final修饰的静态成员变量,在clint执行过程中赋值为代码中指定的值,请问老师是这样的吗?展开
作者回复: 1. 可能我翻译得有点瑕疵,导致了你的误解。这里我指的是扩展器类的 父-类加载器,而不是父类-(加载器)。 2. Java中所有的非私有实例方法,都算是虚方法。调用这些方法的指令,也区分直接调用和虚调用。下一篇我会讲到。 3. 赞一个。被final修饰的静态成员变量,如果不是基本类型或者字符串,也会放在clinit 来做。
共 5 条评论19 - Skysper2018-07-25每次new一个类都是一次初始化吧?加载和链接以后生成的是什么样的数据结构?存储在什么地方?
作者回复: 类的初始化只会发生一次,你可能指的是实例的初始化? JVM并不会直接使用.class文件,类加载链接的目的就是在JVM中创建相应的类结构,会存储在元空间(我之前用的老说法”方法区”,感谢某同学指出)。
共 4 条评论17 - Super丶X2018-07-25老师,你说可以通过不同的类加载器加载同一个类得到类的不同版本,我有个疑问,类是通过包名加类名来使用的,那怎么样区分不同的类加载器加载的类呢?
作者回复: 你指的是在写代码的时候如何区分对吧?我认为没法区分。如果你有一个类的两个不同版本,而且它们不兼容,那么编译时指向哪个,就按哪个来编译。也就是说,如果要同时使用两个版本,那么你需要分开编译。
共 2 条评论11 - Geek_dde3ac2018-07-25请问有什么办法或者工具可以看到类加载的这些过程呢?共 1 条评论10
- 小蛋壳2018-07-26加载阶段都加载哪些类呢,那么多类,全部加载吗?
作者回复: 加载阶段是针对单个类的,一般用到的类才会被加载。大部分情况下,不同类的加载阶段是不同的。
9 - L.B.Q.Y2018-07-25从大的方面讲,类加载的结果是把一段字节流变换成Class结构并写方法区,实际写方法区具体是发生在加载、链接、初始化的哪个环节呢?
作者回复: 在加载阶段就已经生成class结构了,所以我认为应该已经写入了方法区,只是被标记为未链接而暂不能使用。
共 3 条评论7 - Geek_4368732018-12-22看完了整篇文章,其实我还是没搞明白,加载-链接-初始化 这三个步骤的关系。首先我理解加载就是把编译好的.class文件读如jvm内存,存放至方法区。至于链接,我觉得暂时不用去深究。初始化则是比较常见的,我们去new操作或者访问静态变量时会触发类的初始化操作。我的问题是:1.什么时候触发类加载?2:加载-链接-初始化一定是三者都发生的吗,会存在某个累只加载,不链接,不初始化的情况吗共 5 条评论5
- scutware2018-07-26您在评论回复说.class在加载后已经写入方法区(元空间),但是我理解在方法区里类代码的方法调用应该是实际的调用地址吧?而取得实际调用地址不是在链接阶段吗?这里不太理解,求解答~
作者回复: 链接时取得的不是被加载类的地址,而且被加载类所调用的其它方法的地址
共 2 条评论5 - funnyx2018-07-25有两个问题想问一下老师,在类加载的过程中,有一个委派模式,这里严格来说应该不是使用的继承方式,应该是组合。另一个就是类中的静态字段,如果没有被jvm标记为常量,那么这部分内存是如何分配的?
作者回复: 前面那个问题,你说的没错。这么说的原因是它委派的那个对象名字叫parent。可能翻译为双亲比较不容易混淆。 后面那个问题,JVM都会分配内存的,只是初始化的过程不一样,一个是JVM直接赋值,一个是在clinit方法中赋值
5 - airfly2019-02-28没明白java虚拟机和类加载器的关系,共 1 条评论4
- 刹那间的永恒2018-10-23老师,您好!关于classLoader有点疑问,在看源码时发现AppClassLoader和ExtClassLoader都继承自URLClassLoader,这个URLClassLoader是做什么的?另外“委派”是如何实现的了?在AppClassLoader中也没看到ExtClassLoader。共 1 条评论4
- Hero2018-07-26你该加油了,期待接下来精彩……共 2 条评论4