1.调用关系
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
// Returns the class's class loader, or null if none.
static ClassLoader getClassLoader(Class<?> caller) {
// 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();
}
// Package-private to allow ClassLoader access
ClassLoader getClassLoader0() { return classLoader; }
// Initialized in JVM not by private constructor
// This field is filtered from reflection access, i.e. getDeclaredField
// will throw NoSuchFieldException
private final ClassLoader classLoader;
可知Class.forName()是获取调用方法所在的类的类加载器,然后使用该类加载器加载指定的类。
2.示例
自定义类加载器
public class MyClassLoader extends ClassLoader {
private String path;
private String name;
public MyClassLoader(ClassLoader parent, String path, String name) {
super(parent);
this.path = path;
this.name = name;
}
public MyClassLoader(String path, String name) {
super();
this.path = path;
this.name = name;
}
static {
ClassLoader.registerAsParallelCapable();
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = readClassFile2ByteArray(name);
return this.defineClass(name, data, 0, data.length);
}
private byte[] readClassFile2ByteArray(String name) {
InputStream is = null;
byte[] returnData = null;
name = name.replaceAll("\\.", Matcher.quoteReplacement(File.separator));
String filePath = this.path + name + ".class";
File file = new File(filePath);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
is = new FileInputStream(file);
int tmp = 0;
while ((tmp = is.read()) != -1) {
byteArrayOutputStream.write(tmp);
}
returnData = byteArrayOutputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
if (byteArrayOutputStream != null) {
byteArrayOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return returnData;
}
@Override
public String toString() {
return "MyClassLoader{" +
"name='" + name + '\'' +
'}';
}
}
自定义类加载器需要加载的类:
public class Test {
public static int a = 1;
static {
System.out.println(a);
}
public Test() {
System.out.println("A ClassLoader:" + this.getClass().getClassLoader()
+ " from user");
}
public void sayHello() throws ClassNotFoundException {
System.out.println("================");
System.out.println("This is in Test");
Class.forName("com.enjoy.learn.core.jvm.Hello");
Hello hello = new Hello();
System.out.println(hello.getClass().getClassLoader());
System.out.println("================");
}
}
在sayHello中需要加载的类:
public class Hello {
public Hello() {
System.out.println("say hello");
}
}
public class TestClassLoader {
public static final MyClassLoader WZ_LOADER = new MyClassLoader(null,"E:\\IdeaProjects\\javabasics\\target\\classes\\","wz");
public static void main(String[] args) throws Exception {
Class<?> c = WZ_LOADER.loadClass("com.enjoy.learn.core.jvm.Test");
Object obj = c.newInstance();
Method method = c.getMethod("sayHello", null);
method.invoke(obj, null);
}
}
测试结果:
A ClassLoader:MyClassLoader{name='wz'} from user
================
This is in Test
say hello
MyClassLoader{name='wz'}
================
可以看出在Test.sayHello中调用Class.forName方法加载类,使用的是Test的类加载器。
3.注意事项
public static void main(String[] args) throws Exception {
Class<?> c = WZ_LOADER.loadClass("com.enjoy.learn.core.jvm.Test");
Object obj = c.newInstance();
Method method = c.getMethod("sayHello", null);
method.invoke(obj, null);
}
由于c是Class<?>,只能将c.newInstance()赋值给Object obj,而不能是Test。这里需要使用反射来实现调用,比较麻烦。