1.双亲委派机制工作原理
1)、如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行。
2)、如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的的启动类加载器。
3)、如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派机制。
2.工作原理图示
3.简单代码实现:
在项目模块中建立java.lang.String类
package java.lang;
/**
* @program: jvmDemo
* @description
* @author: 不会编程的派大星
* @create: 2021-05-03 13:26
**/
public class String {
static {
System.out.println("我是自己创建的String类");
}
}
然后在测试类中测试:
package parent;
/**
* @program: jvmDemo
* @description
* @author: 不会编程的派大星
* @create: 2021-05-03 13:26
**/
public class ParentTest {
public static void main(String[] args) {
String s = new String();
s = "hello";
System.out.println(s);
System.out.println(s.getClass().getClassLoader());
}
}
执行结果:
可以看到哈,这里是直接打印的hello ,并没有执行代码块,说明这里加载的是核心类string,而不是自定义加载的,并且加载器为null,说明该类的加载器为引导类加载器。
4.优势分析
1、避免类的重复加载(当父ClassLoader已经加载了该类的时候,就没有必要子ClassLoader再加载一次)
2、保护程序安全,防止核心API被随意篡改
(自定义类:java.lang.String | java.lang.ShkStart)
5.沙箱安全机制
我们在刚刚自定义的string类中,加一个main方法执行,报错:
虽然我们自定义了一个java.lang包下的String尝试覆盖核心类库中的String,但是由于双亲委派机制,启动加载器会加载java核心类库的String类(BootStrap启动类加载器只加载包名为java、javax、sun等开头的类),而核心类库中的String并没有main方法
自定义String类,但是在加载子弟敬意String类的时候回率先使用引导类加载器加载,而引导类加载器在加载过程中会先加载jdk自带的文件(rt.jar包中的java\lang\String.class),报错信息说没有main方法就是因为加载的是rt.jar包中的String类。这样可以保证对java核心源代码的保护,这就是沙箱安全机制.
5.如何判断两个Class对象是否相同
这里说明两必要条件:
1.类的完整类名必须一致,包括类名。
2.加载这个类的ClassLoader(指ClassLoader实例对象)必须相同。
换句话说,在jvm中,即使这两个对象来源于同一个Class文件,被同一个虚拟机所加载,但只要加载它们的ClassLoader实例对象不同,那么这两个类也是不相等的。
*JVM必须知道一个类型是由启动加载器加载还是用户类加载器加载的。如果一个类型是又用户类加载器加载的,那么JVM会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中。
6.类的主动使用和被动使用
这一次的讨论就到这里了,欢迎小伙伴们留言讨论!