⑥. 测试不同的类加载器
- ①. 每个Class对象都会包含一个定义它的ClassLoader的一个引用
- ②. 获取ClassLoader的途径
(1). 获得当前类的ClassLoader clazz.getClassLoader() (2). 获得当前线程上下文的ClassLoader(系统类加载器) Thread.currentThread().getContextClassLoader() (3). 获得系统的ClassLoader ClassLoader.getSystemClassLoader()
③. 站在程序的角度看,引导类加载器与另外两种类加载器(系统类加载器和扩展类加载器)并不是同一个层次意义上的加载器,引导类加载器是使用C++语言编写而成的,而另外两种类加载器则是使用Java语言编写而成的。由于引导类加载器压根儿就不是一个Java类,因此在Java程序中只能打印出空值
④. 数组类的Class对象,不是由类加载器去加载的,而是在Java运行期JVM根据需要自动创建的。对于数组的类加载器来说,是通过Class.getClassLoader()返回的,与数组中元素类型的类加载器是一样的;如果数组当中的元素类型是基本数据类型,数组类是没有类加载器的(基本数据类型由虚拟机预先定义)
public class ClassLoaderDemo { public static void main(String[] args) { ClassLoader classloader1 = ClassLoader.getSystemClassLoader(); //sun.misc.Launcher$AppClassLoader@18b4aac2 System.out.println(classloader1); //获取到扩展类加载器 //sun.misc.Launcher$ExtClassLoader@424c0bc4 System.out.println(classloader1.getParent()); //获取到引导类加载器 null System.out.println(classloader1.getParent().getParent()); //获取系统的ClassLoader ClassLoader classloader2 = Thread.currentThread().getContextClassLoader(); //sun.misc.Launcher$AppClassLoader@18b4aac2 System.out.println(classloader2); String[]strArr=new String[10]; ClassLoader classLoader3 = strArr.getClass().getClassLoader(); //null,表示使用的是引导类加载器 System.out.println(classLoader3); ClassLoaderDemo[]refArr=new ClassLoaderDemo[10]; //sun.misc.Launcher$AppClassLoader@18b4aac2 System.out.println(refArr.getClass().getClassLoader()); int[]intArr=new int[10]; //null,如果数组的元素类型是基本数据类型,数组类是没有类加载器的 System.out.println(intArr.getClass().getClassLoader()); } }
③. ClassLoader源码剖析
①. ClassLoader与现有类加载器的关系
- ①. ClassLoader是一个抽象类。如果我们给定了一个类的二进制名称,类加载器应尝试去定位或生成构成定义类的数据。一种典型的策略是将给定的二进制名称转换为文件名,然后去文件系统中读取这个文件名所对应的class文件
- ②. ClassLoader与现有类加载器的关系
- ③. ExtClassLoader并没有重写loadClass()方法,这足矣说明其遵循双亲委派模式
- ④. AppClassLoader重载了loadClass()方法,但最终调用的还是父类loadClass()方法,因此依然遵守双亲委派模式。