类怎么加载的?当然就是通过ClassLoader加载的了。那具体是怎么加载的?这个就不是很清楚了。查了下资料才发现,具体加载模型有个名词,叫双亲委派。意思就是一个类加载器如果收到了加载请求,先找爸妈去加载,而不会自己做这件事。如果它爸妈收到儿女的委派,而且爸妈的爸妈还健在,那么爸妈也不能自己做主,接着请示爸妈的爸妈去加载。每一层加载器都必须先委派给父加载器,只有父加载器找不到要加载的类,才会由下一层加载器处理。我们来看图:
不同加载器搜索的范围不同,启动类加载器只搜JAVA_HOMElib目录,扩展类加载器只搜JAVA_HOMElibext目录,应用程序类加载器只搜classpath目录。双亲委派的目的就是实现加载的优先级,避免同名类加载的混乱,避免通过自定义类加载器来恶意加载类达到替换标准API的目的。如果同一个class文件由不同的类加载器来加载,那么对应会有两个不同的实例。下面看下代码:
package com.wulinfeng.io; import static java.lang.System.out; import java.io.InputStream; import sun.text.resources.cldr.FormatData; public class ClassLoad { public static void main(String[] args) throws Exception { // 加载一个在jre/lib/ext目录下的类FormatData.class Class clzEXT = FormatData.class; ClassLoader loader = clzEXT.getClassLoader(); out.println("FormatData.class的类加载器:" + loader.getClass()); out.println("FormatData.class的类加载器的父母:" + loader.getParent()); // 加载一个在classpath下的类ClassLoad.class Class clzApp = ClassLoad.class; ClassLoader loader2 = clzApp.getClassLoader(); out.println("ClassLoad.class的类加载器:" + loader2.getClass()); out.println("ClassLoad.class的类加载器的父母:" + loader2.getParent()); out.println("ClassLoad.class的类加载器的祖父母:" + loader2.getParent().getParent()); // 自定义类加载器 ClassLoader newLoader = new ClassLoader() { @Override public java.lang.Class<?> loadClass(String name) { try { String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class"; InputStream is = getClass().getResourceAsStream(fileName); if (is == null) { return super.loadClass(name); } byte[] b = new byte[is.available()]; is.read(b); return defineClass(name, b, 0, b.length); } catch (Exception e) { System.err.println(e); } return null; } }; out.println("自定义的类加载器:" + newLoader.getClass()); out.println("自定义的类加载器的父母:" + newLoader.getParent()); out.println("自定义的类加载器的祖父母:" + newLoader.getParent().getParent()); // 使用自定义加载器加载ClassLoad.class,与application加载器得到的实例是不同的 Object o = newLoader.loadClass("com.wulinfeng.io.ClassLoad").newInstance(); out.println(o instanceof com.wulinfeng.io.ClassLoad); } }
输出结果:
FormatData.class的类加载器:class sun.misc.Launcher$ExtClassLoader FormatData.class的类加载器的父母:null ClassLoad.class的类加载器:class sun.misc.Launcher$AppClassLoader ClassLoad.class的类加载器的父母:sun.misc.Launcher$ExtClassLoader@33909752 ClassLoad.class的类加载器的祖父母:null 自定义的类加载器:class com.wulinfeng.io.ClassLoad$1 自定义的类加载器的父母:sun.misc.Launcher$AppClassLoader@73d16e93 自定义的类加载器的祖父母:sun.misc.Launcher$ExtClassLoader@33909752 false