[Java Jvm]Java 类的加载重点记录

一.Java类加载概述

类的加载过程是指,虚拟机把描述类的数据从Class文件中加载到内存,并对数据进行校验,转换解析,和初始化的过程,最终形成可以被虚拟机直接使用的java类型。

Java中,类的加载,连接和初始化过程都是在程序运行期间完成的,这种策略会令类加载时耗时增加性能开销,但提供了更高的灵活性,可以动态扩展,可以在运行时再指定下载的类文件达到动态扩展程序的作用
在这里插入图片描述

二.Java类的生命周期:

在这里插入图片描述

1.加载

a. 通过一个全限定名来获取定义此类的二进制字节流(可以从class文件中读取,也可以从zip,jar,网络等中读取)

b.将字节流所代表的静态存储结构转化为方法区的运行时数据结构

c.在内存(可以是堆可以是方法区,未强制规定,看虚拟机实现)中生成一个代表这类的类对象,作为方法区这个类的各种数据的访问入口.


Link,链接阶段

2.验证:

为了确保Class文件的字节流信息符合要求,且不会有危害(Class文件并非只可以通过java编译而来,还可以是其他生成方式,可以产生恶意语义)

大致过程:文件格式验证,元数据验证,字节码验证,符号引用验证.

重要但非必要,多次验证过的代码可以在实施阶段通过参数将验证关闭,以缩短虚拟机类加载时间.

3.准备:

正式为类变量(被static修饰的变量)分配内存并设置类变量初始值的阶段.(实例变量在类初始化时设置到堆上,常量会在准备阶段设置为指定值)

4.解析:

解析阶段不固定,可以在初始化钱也可以在初始化后进行,是虚拟机将常量池内的符号引用替换为直接引用的过程

将常量池的符号引用替换为直接引用的过程


5.初始化:

初始化阶段是执行类构造器()方法的过程.
<clinit>()方法石油编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器手机的顺序由语句在源文件中出现的顺序所决定,

静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值但不能访问.

<clinit>()无需显示调用父类构造其,虚拟机会保证在子类的()执行之前父类的()方法已经执行完毕.因此虚拟机中第一被执行的()方法的类肯定是Object类.

如果一类中无静态语句块,也没有对变量赋值的操作,编译器可以不为其生成()方法.

初始化阶段,有且只有5种情况必须立即对类进行初始化:

1.遇到new,getstatic,putstatic,invokestatic这4个字节码指令时,如果类没有进行初始化则需要先触发其初始化;
该4条指令的场景:new 实例化对象的时候,读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外),以及调用一个类的静态方法的时候
2.reflect反射调用的时候,如果类没有初始化需要先触发其初始化;
3.当初始化一个类时其父类未初始化则需先触发其父类的初始化;
4.包含main方法的类虚拟机会先初始化这个类;
5.当时用动态语言支持时,解析结果的实例是static相关如果未初始化需要先触发其初始化。

除此之外,所有引用方式都不会触发初始化,称为被动引用:
1.通过子类引用父类的静态变量,不会导致子类初始化
2.通过数组定义来引用类,不会触发此类的初始化
3.常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量类的初始化

6.使用

7.卸载

三.类加载器

判断两个类是否相同,只有在两个类在同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,这两个类就必定不相同.

即:
在JVM中表示两个class对象是否为同一个类对象存在两个必要条件

  1. 类的完整类名必须一致,包括包名。
  2. 加载这个类的ClassLoader(指ClassLoader实例对象)必须相同。

1.类加载器种类

启动类加载器(Bootstrap ClassLoader): 加载<JAVA_HOME>/lib/中的代码,启动类加载器无法被Java程序直接引用.

扩展类加载器(Extension ClassLoader):加载<JAVA_HOME>/lib/ext中的代码,开发者可以直接使用该加载器.

应用程序类加载器(Application ClassLoader):一般称为系统类加载器,负责加载用户类路径上所指定的类库,开发者可直接使用.

如有必要可自己重新定义.

2.双亲委派

如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是吧这个请求委托给弗雷加载器去完成.因此所有类加载请求最终都应传送到顶层的启动类加载器中,只有当父加载器反馈

自己无法完成这个加载请求时(在该加载器的搜索范围中未找到所需要的类),子加载器才会自己去尝试加载.可以有效防止多个加载器加载相同类名的类,保证类的唯一性.
在这里插入图片描述
四类加载器之间的关系:

  1. 启动类加载器,由C++实现,没有父类。
  2. 拓展类加载器(ExtClassLoader),由Java语言实现,父类加载器为null
  3. 系统类加载器(AppClassLoader),由Java语言实现,父类加载器为ExtClassLoader
  4. 自定义类加载器,父类加载器肯定为AppClassLoader。

3.自定义类加载器

需求场景:

  1. 当class文件不在ClassPath路径下,默认系统类加载器无法找到该class文件,需要实现一个自定义的ClassLoader来加载特定路径下的class文件生成class对象。
  2. 当一个class文件是通过网络传输并且可能会进行相应的加密操作时,需要先对class文件进行相应的解密后再加载到JVM内存中,这种情况下也需要编写自定义的ClassLoader并实现相应的逻辑。
  3. 当需要实现热部署功能时(一个class文件通过不同的类加载器产生不同class对象从而实现热部署功能),需要实现自定义ClassLoader的逻辑。

参考:
类的成员变量存在JVM的哪块内存区域:https://blog.csdn.net/q503385724/article/details/87910929
深入理解Java类加载器(ClassLoader): https://blog.csdn.net/javazejian/article/details/73413292

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值