关于类加载器
类加载器的使用
//隐式加载
User user=new User();
//显式加载,并初始化
Class clazz=Class.forName("com.test.java.User");
//显式加载,但不初始化
ClassLoader.getSystemClassLoader().loadClass("com.test.java.Parent
了解类加载器的必要性
开发人员大多数时候并不需要显示地使用类加载器,但了解整个机制对于了解类本身却很有用。
- 遇到java.lang.ClassNotFoundException异常或java.lang.NoClassDefFoundError异常的时候,能够读懂日志
- 通过类加载器进行字节码加解密,或实现更多的功能
命名空间
对于任意一个类都需要由它的类加载器和这个类本身一同确认其再Java虚拟机的唯一性,具体而言,底层通过native方法findLoadedClass0
来完成该操作。意味着每一给类加载器都有自己的独特的命名空间。
沙箱安全机制
Java设计了沙箱安全机制,用于将部分Java代码限定在JVM特定的范围内,严格限制其对系统底层资源的使用,例如CPU,内存,文件系统等。
早期,沙箱是独立的,例如加载远程代码的时候,沙箱负责确保这些代码的隔离。
后来,沙箱机制被进一步完善。具体而言,引入了域、权限组、签名等协议,统一地在系统域进行交互。它很像操作系统的用户态和和核心态的关系。
类加载器的关系
三层结构
从类加载器的三层结构来看,它们之间的关系如下图,在底层的实现中,每一层的类加载器都包含父加载器parent的引用。各个加载器加载的内容不相同,可以使用-XX:+TraceClassLoading
答应。
- 启动类(引导类)加载器,负责加载核心库,它用C++实现,所以也没有对应的Java对象——因而子类的parent引用固定为null。
- 拓展类加载器,从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录下加载类库
- 应用类(系统类)加载器,负责加载各种应用程序类
- 用户自定义类加载器,父加载器默认是应用类加载器
代码继承关系
![image.png](https://img-blog.csdnimg.cn/img_convert/16a64b49811f59931301ab79da00ab4c.png#clientId=u5925fd29-86df-4&from=paste&height=449&id=uaa91e2de&margin=[object Object]&name=image.png&originHeight=449&originWidth=565&originalType=binary&ratio=1&size=258886&status=done&style=none&taskId=ub3a65416-1609-43e5-bde3-760c75e08c9&width=565)
从源码角度理解双亲委派机制
双亲委派模型是Java类加载中遵循的加载模型——按照三层结构,一个类加载器在接到加载类的请求时,它首先不会自己尝试去加载这个类,而是把这个请求任务委托给父类加载器去完成,依次递归,如果父类加载器可以完成类加载任务,就成功返回。只有父类加载器无法完成此加载任务时,才自己去加载。
源码理解
从代码继承关系来看,ClassLoader提供了一个共有的类加载器的抽象模板。该类的实现也非常简单,核心代码只有一个——loacClass
。
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 查看该类是否被当前加载器加载
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
// 如果父加载器存在,则调用父加载器的方法
if (parent != null) {
c = parent.loadClass(name, false);
} else {
// 父加载器 == null,说明是引导类加载器,查看引导类加载器是否加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
// 当前类加载器的父加载器未加载国,且尝试加载,加载失败,