实验
Bar1.java
package com.external;
public class Bar1 {
public Bar1(){
Bar2 bar2 = new Bar2();
bar2.test();
}
}
Bar2.java
package com.external;
public class Bar2 {
public void test(){
System.out.println("bar2");
}
}
Bar1.java和Bar2.java这2个类是工程外的代码,由工程里的SimpleClassLoader2定义;
package com.snda.classloader;
import com.snda.util.FileUtils;
import sun.misc.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class SimpleClassLoader2 extends ClassLoader {
public SimpleClassLoader2() {
super(getSystemClassLoader());
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
System.out.println("SimpleClassLoader2 loadClass: " + name);
return super.loadClass(name, resolve);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String rootdir = System.getProperty("user.dir");
try{
byte[] bytes = FileUtils.InputStream2ByteArray(rootdir + File.separator + "external" +
File.separator + name.replace(".", File.separator) + ".class");
return defineClass(name, bytes, 0, bytes.length);
} catch (Exception e){
e.printStackTrace();
}
return null;
}
public static void main(String[] args){
try{
SimpleClassLoader2 classLoader = new SimpleClassLoader2();
// ClassLoader classLoader = new ClassLoader(classLoader2){};
Class<?> barTestClass = classLoader.loadClass("com.external.Bar1");
System.err.println(invoke(classLoader, "com.external.Bar1"));
Object barTest = barTestClass.newInstance();
barTest.toString();
Thread.sleep(3000);
System.out.println("findLoadedClass:" + invoke(classLoader, "java.lang.Object"));
} catch (Exception e){
e.printStackTrace();
}
}
private static Object invoke(Object object, String name){
try {
Method method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
method.setAccessible(true);
return method.invoke(object, name);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
输出:
SimpleClassLoader2 loadClass: com.external.Bar1
class com.external.Bar1(Bar1是由SimpleClassLoader2定义的,findLoadedClass一定会返回)
SimpleClassLoader2 loadClass: java.lang.Object
SimpleClassLoader2 loadClass: com.external.Bar2
SimpleClassLoader2 loadClass: java.lang.System
SimpleClassLoader2 loadClass: java.io.PrintStream
bar2(Bar2类的输出)
findLoadedClass:class java.lang.Object(Object为被动加载,SimpleClassLoader2会被标记为该类的初始类加载器,因而findLoadedClass一定会返回)
结论
findLoadedClass官方文档的解释:
Returns the class with the given binary name if this loader has been recorded by the Java virtual machine as an initiating loader of a class with that binary name.
经过实践,结论如下:
1.Class的getClassLoader方法返回的是该类的定义类加载器,不是初始类加载器;
2.某个Class引用的其他类也会由该Class的getClassLoader方法返回的类加载器加载,因而也是由该Class的定义类加载器发起加载;
2.主动调用ClassLoader的loadClass加载一个类,但该ClassLoader并不是被加载类的定义类加载器,那么后面该ClassLoader的findLoadedClass方法总是回返回null;如果该ClassLoader是被加载类的定义类加载器,则findLoadedClass会返回对应的Class;
3.如果是JVM自己根据类加载机制加载的Class,那么被加载类的初始类加载器(initiating loader)和被加载类的定义类加载器(defining loader),它们的findLoadedClass均会返回被加载的Class;
思考:
1.根据官方文档的说明,如果是初始类加载器,按说findLoadedClass都会返回对应的Class,但根据结论1其并未返回,所以我猜测在主动调用加载Class情况下,并没有标记对应的初始类加载器;
2.调用loadClass的加载器和定义类加载器之间,如果还有别的类加载器,它们都不会被标记为被加载类的初始类加载器,它们的findLoadedClass都会返回null;
具体参考https://stackoverflow.com/questions/21962631/findloadedclass-returns-null