JVM(三、双亲委派机制)
javadoc的解释:
ClassLoader的每一个实例都会有一个与之关联的父ClassLoader,当被要求去寻找一个类或者资源的时候,ClassLoader的实例就会对于类或者是资源的寻找委托给他的父ClassLoader(在他自己尝试找这个类或者资源之前),并层层向上委托。
虚拟机内建的ClassLoader即Bootstrap根类加载器,他本身是没有双亲的,但是他可以作为一个类加载器的双亲。
支持并发加载类的类加载器,被称为 parallel capable class loaders ,被要求在类的初始化期间调用ClassLoader.registerAsParallelCapable()将自身注册为parallelcapableclassloader。 ClassLoader默认是并发类加载器,但他的子类如果是并发的,还依然需要注册。
当境委派模型并不是严格的层次委派模型时,要求类加载器必须是支持并行的类加载器,否则类加载就会导致死锁。因为加载器的锁(loader lock我也不知道咋翻译)在类的加载过程中一直不会释放。
一般来说jvm虚拟机加载类来源于本地文件系统(与操作系统跟平台相关),但也可能来源于其他资源,比如网络,或者运行时的动态生成。
在这种情况下,加载类的方法会把一个字节数组(调用 loadClassData() 返回byte[] ,通过defineClass(byte[])转为一个Class)转换为一个class对象,通过Class.newInstance 来创建对应对象。
class NetworkClassLoader extends ClassLoader { public Class findClass(String name) { private byte[] loadClassData(String name) { } |
由类加载器创建的对象,其方法或者构造器可能引用了其他未加载的类,为了确定这些引用是什么(注意这些引用对应的类还未被装入,需要确定这些引用是什么) jvm虚拟机会调用加载这个类的class的classloader 来加载这些引用(再次跳入第一步 开始递归)
1.获取ClassLoader
1 public class MyTest06 { 2 3 public static void main(String[] args) { 4 String str = new String("212"); 5 C c = new C(); 6 System.out.println(str.getClass().getClassLoader()); 7 System.out.println(c.getClass().getClassLoader()); 8 } 9 10 } 11 class C{ 12 13 }//out: null
sun.misc.Launcher$AppClassLoader@2a139a55
第二个返回值说明自定义类C是由AppClassLoader 系统类加载器加载
第一个返回值说明String由Bootstrap根加载器加载
/** 如下是源码中对 getClassLoader() 方法的说明 * Returns the class loader for the class. Some implementations may use * null to represent the bootstrap class loader. This method will return * null in such implementations if this class was loaded by the bootstrap * class loader. * 如果类由bootstrap class loader加载 这个方法会返回null在一些jvm实现中 * * <p> If a security manager is present, and the caller's class loader is * not null and the caller's class loader is not the same as or an ancestor of * the class loader for the class whose class loader is requested, then * this method calls the security manager's {@code checkPermission} * method with a {@code RuntimePermission("getClassLoader")} * permission to ensure it's ok to access the class loader for the class. * * <p>If this object * represents a primitive type or void, null is returned. * * @return the class loader that loaded the class or interface * represented by this object. * @throws SecurityException * if a security manager exists and its * {@code checkPermission} method denies * access to the class loader for the class. * @see java.lang.ClassLoader * @see SecurityManager#checkPermission * @see java.lang.RuntimePermission */
2.ClassLoader.loadClass()方法与Class.forName()方法
class CL{ static { System.out.println("class cl"); } } public class MyTest07 { public static void main(String[] args) throws Exception { ClassLoader clazzloader = ClassLoader.getSystemClassLoader(); Class<?> clazz = clazzloader.loadClass("jvm.CL"); System.out.println("=================================="); System.out.println(clazz); System.out.println("=================================="); Class<?> clazz2 = Class.forName("jvm.CL"); System.out.println("=================================="); System.out.println(clazz2); } }//out: ================================== class jvm.CL ================================== class cl ================================== class jvm.CL
loadclass 只加载对应类,forName 会一并将类初始化
不过调用 clazz.newInstance()会初始化该类:
public class MyTest07 { public static void main(String[] args) throws Exception { ClassLoader clazzloader = ClassLoader.getSystemClassLoader(); Class<?> clazz = clazzloader.loadClass("jvm.CL"); System.out.println("=================================="); System.out.println(clazz); System.out.println("=================================="); clazz.newInstance(); System.out.println("=================================="); Class<?> clazz2 = Class.forName("jvm.CL"); System.out.println("=================================="); System.out.println(clazz2); } }out: ================================== class jvm.CL ================================== class cl ================================== ================================== class jvm.CL
3.HotSpot实现中用null代替根加载器Bootstrap
public class MyTest08 { public static void main(String[] args) { ClassLoader classloader = ClassLoader.getSystemClassLoader(); System.out.println(classloader); while(classloader!=null) { classloader= classloader.getParent(); System.out.println(classloader); } } }//out: sun.misc.Launcher$AppClassLoader@2a139a55 sun.misc.Launcher$ExtClassLoader@7852e922 null
4.数组的classloader,数组是JVM在运行时动态生成的类型,没有类加载器,如果调用getClassLoader会返回对应元素的类加载器。
public class MyTest09 { public static void main(String[] args) { String[] strs = new String[2]; System.out.println(strs.getClass().getClassLoader()); System.out.println("============================"); MyTest09[] ms = new MyTest09[2]; System.out.println(ms.getClass().getClassLoader()); System.out.println("============================"); int[] ints = new int[2]; System.out.println(ints.getClass().getClassLoader()); } }//out: null ============================ sun.misc.Launcher$AppClassLoader@2a139a55 ============================ null
其中String类型的类加载器是Bootstrap 在HotSpot实现中被表现为null
源生类型则没有类加载器。
5.类加载器一般都会伴随一个安全管理器,来确保类加载过程中是安全的