[JavaEE初阶] 类加载机制

在真正的战争到来之前,尽可能地变得强大吧~


前言

这个问题是面试经典题,让我们来求甚解吧~


1. 类加载

1.1 类加载的过程

如下图
在这里插入图片描述

  1. 加载,找到.class文件,读取文件内容
  2. 验证,验证.class文件的格式是否符合JVM虚拟机规范,确保加载了该 class 文件不会导致 JVM 出现任何异常,不会危害JVM 的自身安全。
  3. 准备,给类中的静态变量分配内存空间,这里是在方法区为类对象开辟空间,并将对象值初始化成零值.即int型初始化为0,引用型初始化为null.
  4. 解析,将常量池的符号引用转为直接引用.在这之前,这个引用记录的并不是字符串常量的真正地址,而是记录在文件中的相对偏移量,相当于先占个位置.类加载之后,才真正把字符串常量的地址放进去.这个引用才被真正的赋值成内存地址.
  5. 初始化,类加载的最后一步,执行Java代码,这时,才真正的对类对象进行初始化.此阶段会根据代码进行类变量和其他资源的初始化.编译器收集的顺序是由语句在源文件中出现的顺序决定的.

观察下图的执行结果
在这里插入图片描述
在这里插入图片描述
改变顺序,结果改变
在这里插入图片描述
在这里插入图片描述

1.2 类加载的时机

遇到 new、getstatic、putstatic、invokestatic 字节码指令,例如:使用 new 实例化对象;
读取或设置一个类的 static 字段(被 final 修饰的除外);
调用类的静态方法。
对类进行反射调用;
初始化一个类时,其父类还没初始化(需先初始化父类);
这点类与接口具有不同的表现,接口初始化时,不要求其父接口完成初始化,只有真正使用父接口时才初始化,如引用父接口中定义的常量。

虚拟机启动,先初始化包含 main() 函数的主类;

1.3 双亲委派模型

如下图,是JVM默认提供的三种类加载器.它们存在父子关系.
在这里插入图片描述
加载一个类的时候,从ApplicationClassLoader开始,但ApplicasionClassLoader会先把加载任务交给父亲ExtensionClassLoader去完成.
ExtensionClassLoader要加载了,他也把这个任务交给他的父亲BootstrapClassLoader去完成.
接着,BootstrapClassLoader也想交给自己的父亲,但他发现自己父亲为空,就只能去搜索自己负责的标准库目录的相关的类,找到的就加载,没找到的,就交给子类加载器进行加载.
之后,ExtensionClassLoader去搜索与扩展库相关的目录,如果找到就加载,没找到的,交给子类加载器进行加载
之后,Applicaton开始真正搜索与用户项目有关的目录,找到了,就加载,找不到,就会报错了.

那么,为什么要这么麻烦,不是直接从上到下的呢?由于JVM使用递归来实现的,所以,才导致了这个顺序.另外,先加载底层的类,能保证,当用户代码出错时,只需修改用户代码即可,不会出现太严重的bug.如果用户写了与标准库重名的一些类,由于执行顺序,JVM加载的还是标准库中的类,不会用用户自己写的类.并且,用户可以自定义类加载器,将自己的类加载器加入上述流程中,与自带的类加载器配合使用.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值