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 {
  String host;
  int port;

public Class findClass(String name) {
  byte[] b = loadClassData(name);
  return defineClass(name, b, 0, b.length);
}

private byte[] loadClassData(String name) {
  // load the class data from the connection

}
}

 

由类加载器创建的对象,其方法或者构造器可能引用了其他未加载的类,为了确定这些引用是什么(注意这些引用对应的类还未被装入,需要确定这些引用是什么) 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.类加载器一般都会伴随一个安全管理器,来确保类加载过程中是安全的

 

posted @ 2019-04-02 18:41  茶饭不撕  阅读(652)  评论(0编辑  收藏  举报