JavaSE之类加载器
类加载器
概念
Java文件被编译成 .class文件(字节码文件),类加载器就是负责将.class文件(存储的物理文件)加载在到内存中
类加载时机
-
创建类的实例(对象)
-
调用类的类方法(静态方法)
-
访问类或者接口的类变量(静态变量),或者为该类变量赋值
-
使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
-
初始化某个类的子类
-
直接使用java.exe命令来运行某个主类
用到就加载,不用不加载
类加载的过程
(1)加载
通过一个类的全限定名来获取此类的二进制字节流
将这个字节流所代表的静态存储结构转换为运行时数据结构
在内存中生成一个代表这个类的java.lang.Class对象(任何类被使用时,系统都会未知创建一个java.lang.Class对象)
简单的说就是:
-
通过包名 + 类名,获取这个类,准备用流进行传输
-
在这个类加载到内存中
-
加载完毕创建一个class对象
(2)链接
验证
确保Class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全
(文件中的信息是否符合虚拟机规范有没有安全隐患)
准备
负责为类的类变量(被static修饰的变量)分配内存,并设置默认初始化值(null)
(初始化静态变量)
解析
将类的二进制数据流中的符号引用替换为直接引用
(本类中如果用到了其他类,此时就需要找到对应的类)
如下案例,有一个Student对象,要将其加载到内存,地址值假设为0x0011,String是一个引用数据类型
所以在之前的加载过程中,会将String标记成符号,而在解析过程中,会对该符号进行解析,假设String的Class类对象是在内存的0x0022的位置
就会把之前在该位置的符号引用变成直接引用,即将&&&变成0x0022。
(3)初始化
根据程序员通过程序制定的主观计划去初始化类变量和其他资源
(静态变量赋值以及初始化其他资源)
之前定义的静态变量在准备阶段的值为null,附上程序设定的初始值为 "华南理工大学"
static String school = "华南理工大学";
类加载器的类型
-
Bootstrap class loader:虚拟机的内置类加载器,底层是用C++实现的,没有父加载器
-
Platform class loader:平台类加载器,负责加载JDK中一些特殊的模块
-
System class loader:系统类加载器,负责加载用户类路径上所指定的类库
System的父加载器为Platform,Platform的父加载器为Bootstrap
即:启动类加载器是平台类加载器的父加载器;平台类加载器是系统类加载器的父加载器;系统类加载器是的自定义类加载器的父加载器。
注意这里的父子关系并不是代码中的extends的关系,而是逻辑上的父子。
注意Java9之前的版本关于类加载器的说法是有不同的!!!这里上述是讲Java9的类加载器
Java9类加载器https://zhuanlan.zhihu.com/p/97650770
JDK8与JDK9在类加载器上的区别
Java8的类加载机制如下
- 引导类加载器(boostrap class loader):虚拟机内置的类加载器,通常以
null
表示,从引导类路径加载。 - 扩展类加载器(extension class loader):从扩展目录加载类。它是JDK 1.2中引入的扩展机制的产物。它的父类加载器为引导类加载器。
- 应用类加载器(application class loader):从应用的CLASSPATH中加载类。它的父类加载器为扩展类加载器。
Java9的类加载机制如下
Java 9仍然保留了三层类加载器结构,不过为了支持模块系统,对它们做了一些调整。扩展机制被移除,扩展类加载器由于向后兼容性的原因被保留,不过被重命名为平台类加载器(platform class loader)。可以通过ClassLoader
的新方法getPlatformClassLoader()
来获取。
Java 9中,平台类加载器和系统类加载器不再是URLClassLoader
类的对象。这会影响一个常见的用来在运行时向系统类加载器的查找路径中添加条目的hack。在下面的代码中,该hack把系统类加载器转型成URLClassLoader
并调用其addURL()
方法。该hack在Java 9无法工作,因为转型为URLClassLoader
会失败。
双亲委派模型
如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式
Coding演示
Java8版本的
public class demo {
public static void main(String[] args) {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
ClassLoader classLoader1 = systemClassLoader.getParent();
ClassLoader classLoader2 = classLoader1.getParent();
System.out.println(systemClassLoader);
System.out.println(classLoader1);
System.out.println(classLoader2);
}
}
而Java9版本的
详细的区别见下
Java9类加载器https://zhuanlan.zhihu.com/p/97650770
ClassLoader 中的两个方法
方法名 | 说明 |
---|---|
public static ClassLoader getSystemClassLoader() | 获取系统类加载器 |
public InputStream getResourceAsStream(String name) | 加载某一个资源文件 |
Coding
public class Demo{
public static void main(String[] args) throws IOException {
//static ClassLoader getSystemClassLoader() 获取系统类加载器
//InputStream getResourceAsStream(String name) 加载某一个资源文件
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
//利用加载器去加载一个指定的文件
//参数:文件的路径(放在src的根目录下,默认去那里加载)
//返回值:字节流。
InputStream is = systemClassLoader.getResourceAsStream("prop.properties");
Properties prop = new Properties();
prop.load(is);
System.out.println(prop);
is.close();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)