日常记录——JVM—类加载器工作原理

一、简介

类加载器:负责读取 Java 字节代码文件(.class),并转换成 java.lang.Class 类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance() 方法就可以创建出该类的一个对象。即将对应类的.class文件中的二进制流加载到内存空间。

二、类加载器分类

类加载器一共有四种:
1.Bootstrap ClassLoader :引导类加载器,它用来加载 Java 的核心库(存放在<JAVA_HOME>\lib目录中),是用原生代码来实现的,并不继承自 java.lang.ClassLoader 。
2.Extension ClassLoader:扩展类加载器,负责加载<JAVA_HOME>\lib\ext目录下的类库,扩展类库,继承自ClassLoader。。
3.Application ClassLoader:应用程序类加载器,加载开发者自定义的类库(classpath)。一般情况下这个就是程序中默认的类加载器,继承自ClassLoader。
4.自定义类加载器:继承ClassLoader,自定义实现方式。

三、工作原理

一个class文件被类加载器加载到内存分为以下三步骤:
1.loading:加载
将.class文件加载至运行时的方法区,在堆中创建一个Java.lang.Class对象,每个类都对应有一个Class类型的对象,即可通过反射访问方法区内对应类信息。
(1)loading原理:双亲委派原理,指的就是类接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
在这里插入图片描述

解释:一个类申请加载(这里没有自定义加载器的逻辑),首先Application 加载器去自己缓存查找是否加载过,如果是返回一个class实例,如果没找他的父加载器(每个ClassLoader对象都有一个parent属性,为当前加载器的父加载器)直到Bootstrap加载器,缓存还不存在,判断是否自己加载范围,是寻找class文件,加载,否则抛出ClassNotFoundException异常,不是自己加载范围则让子加载器加载,直到Application加载器。
(2)为什么要遵循双亲委派原理?
A.安全:如果我自定义一个String类,直接就加载,那么JDK类库的String就被我覆盖了,如果我在里面构造方法写获取信息等操作,自然只要使用这个类,我就能获取到信息。遵循双亲委派,则String类只会从JDK类库中被Bootstrap加载器加载,保障安全。
B.保证只加载一次:如果同一个类多次申请都加载一次,效率低并且消耗内存,遵循双亲委派则同一类只会加载一次。同一类确保机制为类名+类加载器(使用同一加载器加载同一类名的类,即为同一类)。
2.linking:连接
连接分为三步:
(1)verification:验证,验证class文件规范。
(2)preparation:准备,为类的静态变量分配内存,并初始化为默认值(static int a = 1 这里a=0)。
(3)resolution:解析,将符号引用转成直接引用(A类引用了B类,编译时A并不知道B类实际的内存地址,使用能唯一识别B的符号来代替,但访问不到。而当类加载时,编译后的.class文件实际已被调入内存,可知B类的实际内存地址,当引用的目标已被加载入内存,则此时的引用为直接引用,可以访问到)。
3.initializing:初始化
初始化过程为类的静态变量赋予正确的初始值(static int a = 1 准备阶段a=0,现在a=1)。
整体流程图:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43001336/article/details/107454152
今日推荐