双亲委派机制概述
- Java虚拟机对class文件采用按需加载的方式,也就是说当需要使用该类时,才会将它的class文件加载到内存生成class对象。而且加载某个类的文件是,采用的是双亲委派机制,即把请求交由父类处理,它是一种任务委派模式。
- 先看下面的一个例子
新建一个 java.lang 包,在下面自定义一个String类 ,如图 然后在Test中创建String类
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
String string = new String();
java.lang.String s2 = new java.lang.String();
System.out.println("hello");
}
}
如果创建的对象是我们自定义的类则会输出静态代码块中的 ““我是自定义 String …””,否则不会。 这里结果指定是不会打印的,这就是双亲委派机制的作用。
双亲委派机制原理
- 如果一个类加载器接收到了类加载请求,它并不会自己先去加载,而是把这个类加载委托给父类加载器去执行。
- 如果父类加载器还存在父加载器,则进一步向上委托,依次递归,请求将最终达到顶层的启动类加载器。
- 如果父类可以完成类加载任务,就成功返回,若父类无法完成类加载任务,子加载器才会尝试去加载,这就是双亲委派模式。
- 如果将上面的代码 main方法放在自定义的 String 类中
public class String {
static {
System.out.println("我是自定义 String ...");
}
public static void main(String[] args) {
System.out.println("main....");
}
}
执行的时候报错如下:
意思就是加载的 java.lang.String 类中没有 main方法,也证明了之前的结论。
双亲委派机制的优势
- 避免类重复加载
- 保护程序安全,避免核心API被随意篡改。(如上面的自定义 java.lang.String 类)也包括阻止我们使用和核心api相同的包名来自定义类。
如下图 报错如下:
Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:662)
at java.lang.ClassLoader.defineClass(ClassLoader.java:761)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at Test.main(Test.java:5)
沙箱安全机制
- 自定义String类,但是在加载自定义String类时会率先使用引导类加载器加载,而引导类加载器在加载过程中会优先加载jdk自带的文件,上面例子报错信息说没有 main 方法,就是因为加载的是 jdk的 java.lang包下的String类。这样可以保证java源码的保护,这就是沙箱安全机制。
|