不看源码,以为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
两次加载使用的不是同一个类加载器,而是调用者的类加载器。