双亲委派机制的工作原理:
- 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行;
- 如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将要到达顶层的启动类加载器;
- 如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式.
举个例子:
假如你自定义了Java.lang.String类,在String类被调用的过程中依然会使用默认的String类;因为双亲委派原则,所以这个类的加载会向上委托到BootstrapClassLoader,而Bootstrap ClassLoader(启动类加载器)加载包名为java,javax,sum等开头的类,所以由BootstrapClassLoader来加载,从而加载的是核心类库的String类,非自定义的String类;
如果自定义的类所在的包,不在BootstrapClassLoader的加载范围就会交回子加载器ExtensionClassLoader,依此类推直到找到对应加载范围的类加载器.(对于用户自定义类来说:默认使用系统类加载器进行加载)
双亲委派机制的优势
由上面的`例子,可以看出:
-
能避免类的重复加载
-
保护程序安全,防止核心API被随意篡改
沙箱安全机制
根据上面的例子分析,自定义String类但是加载自定义String类的时候会向上委托给启动类加载器加载,而启动类加载在加载的过程中会先加载jdk自带的文件(rt.jar包中java\lang\String.class),如果在自定义String类运行类中的main方法会报错说没有main方法,因为加载的是rt.jar包中的String类.这样可以保证对java核心源代码的保护,这就是沙箱安全机制.类似将java核心源代码放在一个"沙箱"里去操作,外界的干扰不影响java的核心源代码.(个人认为只是不同角度的解读,跟双亲委派机制一样的东西)
扩展:
在JVM中表示两个class对象是否为同一个类存在两个必要条件:
- 类的完整类名必须一致,包括包名;
- 加载这个类的ClassLoader(指ClassLoader实例对象)必须相同.
也就是说,在JVM中,即使两个类对象来源同一个Class文件,被同一个虚拟机所加载,但只要加载它们的ClassLoader实例对象不同(如自定义的类加载器),那么这两个对象也是不相等的.