Java类加载机制

26 篇文章 0 订阅

重点补充:类加载机制

类加载指的是JVM加载字节码(class文件)的过程。

在这里插入图片描述

  • 这张图是java类的生命周期图,完整一点可以在加载前面加上javac编译这个过程。

  • 类加载只包括加载、连接、初始化。注意区分加载和类加载的区别,加载只是类加载的一个过程

  • 其中解析部分是灵活的,它可以在初始化之前或之后再进行,实现"后期绑定"。其他顺序不可改变。

逐个了解:

加载

加载是一个读取class文件,将其转化为某种静态数据结构存储在方法区内,并在堆中生成一个便于用户调用的java.lang.Class类型对象的过程。
在这里插入图片描述

验证验证有很多个步骤,分散在各个不同的阶段内

前言:对文件格式的检验其实是发生在加载阶段的,如果通过,才能顺利加载,顺利加载后此时方法区虽然已经存在了该class的静态结构,堆中也存在了该class类型对象,但这并不代表着JVM已经完全认可了这个类,如果程序想要使用这个类,就必须进行连接。

连接的第一步就是对这个类进行进一步的验证,继续对方法区内的class静态结构进行了元数据验证、字节码验证,如果通过,JVM则暂且认为它是安全的。(内容:对class静态结构进行语法和语义上的分析,保证其不会产生危害虚拟机的行为)

还有一道验证,是在解析阶段发生的符号引用验证

一般共4个验证,验证的内容是会不断发展的,从低版本的虚拟机到现在验证步骤其实已经不断加入了各种机制,在未来,虚拟机开发人员可能会引入更多更完善更完美的验证策略。

准备

为该类型中定义的静态变量赋0值,这里仅仅是静态变量,而不是成员变量。

**拓展:**虚拟机内存规范中定义了方法区这种抽象概念,JDK8之前使用了永久代这种具体的实现方式来实现了方法区,在JDK8以后弃用了“永久代”这种实现方式,采用“元空间”这种直接内存来取代。所以“JDK8及以后采用元空间来替代方法区”这个说法是错误的,因为方法区是抽象概念,而元空间是具体的实现方式,这种说法是完全牛头不对马嘴的。

解析:

将符号引用替换为直接引用

当一个类被编译成class类,假如这个类为A.class,并且A中引用了B,那么在编译阶段,A是不知道B有没有被编译的,而且此时B也一定没有被加载,所以A肯定不知道B的实际地址,那么A如何才能找到B呢?此时在A的class文件中,将使用一个字符串S来表示B的地址,S就被称为“符号引用”。在运行时,如果A发生了类加载,到了解析阶段会发现B还没有被加载,那么就会触发B的类加载,将B加载到虚拟机中,此时A中B的符号引用会被替换成B的实际地址,这被称为“直接引用”,这样之后A就能真正调用到B了。

多态中的“后期绑定”是如何实现的呢?其实就是这里的动态解析:

如果A调用的B是一个具体的实现类,那么就称为“静态解析”,因为解析的目标类很明确。而加入上层java代码使用了多态,这里的B可能是一个抽象类或者是接口,那么它可能有两个具体的实现类C和D,此时B的具体实现并不明确,当然不知道该使用哪个类的直接引用来进行替换,既然不知道,那就等等咯,直到运行过程中发生了调用,此时虚拟机调用栈中将会得到具体的类型信息,就能用明确的直接引用来替换符号引用了,这时候再进行解析,所以就出现了上面的情况,解析又时候会发生在初始化阶段之后,这就是动态解析,用它来实现了上层的后期绑定和多态,底层对应了invokedynamic这条字节码指令。

画个图理解一下:

在这里插入图片描述

初始化:此时会判断代码中是否有主动的资源初始化(赋值)动作,如果有那么执行,这里的主动资源初始化动作不是指构造函数,而是class层面的,比如说成员变量的赋值动作,静态变量的赋值动作,以及静态代码块的逻辑,而只有调用new才会调用构造函数进行对象的实例化,这是对象层面的,二者不要混淆。

文章参考视频
https://www.bilibili.com/video/BV14U4y1L75q?spm_id_from=333.337.search-card.all.click

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值