不看源码,以为Class.forName(String className)使用的是系统类加载器,看了源码才知道不是这么回事。
public static Class<?> forName(String className) throws ClassNotFoundException { return forName0(className, true, ClassLoader.getCallerClassLoader()); }通过 ClassLoader.getCallerClassLoader()获取类加载器:
// Returns the invoker's class loader, or null if none. // NOTE: This must always be invoked when there is exactly one intervening // frame from the core libraries on the stack between this method's // invocation and the desired invoker. static ClassLoader getCallerClassLoader() { // NOTE use of more generic Reflection.getCallerClass() Class caller = Reflection.getCallerClass(3); // This can be null if the VM is requesting it if (caller == null) { return null; } // Circumvent security check since this is package-private return caller.getClassLoader0(); }看第一行注释,返回的是调用者的类加载器。显然,调用者的类加载器不一定是系统类加载器,比如我们使用了自定义类加载器。看下面的例子:
User.java
package org.zzj; public class User { }UserService.java
package org.zzj; public class UserService { public void add() { try { System.out.println(Class.forName("org.zzj.User").getClassLoader()); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }ClassForNameTest.java
package org.zzj; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; public class ClassForNameTest { public static void main(String[] args) throws Exception { System.out.println(Class.forName("org.zzj.User").getClassLoader()); MyClassLoader classLoader = new MyClassLoader(); Class<?> clazz = classLoader.loadClass("org.zzj.UserService"); Method method = clazz.getMethod("add"); method.invoke(clazz.newInstance()); } } class MyClassLoader extends ClassLoader { @Override public Class<?> loadClass(String name) throws ClassNotFoundException { String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class"; InputStream in = getClass().getResourceAsStream(fileName); if (in == null) { return super.loadClass(name); } byte[] b = null; try { b = new byte[in.available()]; in.read(b); in.close(); } catch (IOException e) { e.printStackTrace(); } return defineClass(name, b, 0, b.length); } }输出:
sun.misc.Launcher$AppClassLoader@19821f org.zzj.MyClassLoader@14318bb两次加载使用的不是同一个类加载器,而是调用者的类加载器。