public class ClassLoaderTest {
public static void main(String[] args) throws Exception{
ClassLoader myLoader = new ClassLoader() {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
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 (IOException e){
throw new ClassNotFoundException(name);
}
}
}; Object obj = myLoader.loadClass("editor4_1.test.jvm.ClassLoaderTest").newInstance(); ClassLoaderTest classLoaderTest = new ClassLoaderTest();
System.out.println("classLoaderTest's classLoader is " + classLoaderTest.getClass().getClassLoader());
System.out.println("obj's classLoader is " + obj.getClass().getClassLoader()); System.out.println(obj instanceof ClassLoaderTest);
}
}
输出结果为:
classLoaderTest's classLoader is sun.misc.Launcher$AppClassLoader@513cf0
obj's classLoader is editor4_1.test.jvm.ClassLoaderTest$1@79ed7f
false
本类中自己定义了ClassLoaderTest这个类加载器,从输出结果中可以看出AppClassLoader加载了classLoaderTest的类,而ClassLoaderTest加载了obj对应的类。
根据双亲委派机制,当加载obj对应的类的时候应该按照这个顺序:Bootstrap ClassLoader, Extension ClassLoader, Application ClassLoader,ClassLoaderTest来进行加载,我的疑问是在Application ClassLoader已经加载了classLoaderTest所对应的类,那obj对应的类在此时就应该被找到了,所以obj的类加载器应该是AppClassLoader才对,可是为什么是ClassLoaderTest呢?
public static void main(String[] args) throws Exception{
ClassLoader myLoader = new ClassLoader() {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
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 (IOException e){
throw new ClassNotFoundException(name);
}
}
}; Object obj = myLoader.loadClass("editor4_1.test.jvm.ClassLoaderTest").newInstance(); ClassLoaderTest classLoaderTest = new ClassLoaderTest();
System.out.println("classLoaderTest's classLoader is " + classLoaderTest.getClass().getClassLoader());
System.out.println("obj's classLoader is " + obj.getClass().getClassLoader()); System.out.println(obj instanceof ClassLoaderTest);
}
}
输出结果为:
classLoaderTest's classLoader is sun.misc.Launcher$AppClassLoader@513cf0
obj's classLoader is editor4_1.test.jvm.ClassLoaderTest$1@79ed7f
false
本类中自己定义了ClassLoaderTest这个类加载器,从输出结果中可以看出AppClassLoader加载了classLoaderTest的类,而ClassLoaderTest加载了obj对应的类。
根据双亲委派机制,当加载obj对应的类的时候应该按照这个顺序:Bootstrap ClassLoader, Extension ClassLoader, Application ClassLoader,ClassLoaderTest来进行加载,我的疑问是在Application ClassLoader已经加载了classLoaderTest所对应的类,那obj对应的类在此时就应该被找到了,所以obj的类加载器应该是AppClassLoader才对,可是为什么是ClassLoaderTest呢?
LZ可以看看javadoc的说明
loadClass
protected Class<?> loadClass(String name,
boolean resolve)
throws ClassNotFoundException使用指定的二进制名称来加载类。此方法的默认实现将按以下顺序搜索类: 调用 findLoadedClass(String) 来检查是否已经加载类。在父类加载器上调用 loadClass 方法。如果父类加载器为 null,则使用虚拟机的内置类加载器。 调用 findClass(String) 方法查找类。如果使用上述步骤找到类,并且 resolve 标志为真,则此方法将在得到的 Class 对象上调用 resolveClass(Class) 方法。 鼓励用 ClassLoader 的子类重写 findClass(String),而不是使用此方法。
参数:
name - 类的二进制名称
resolve - 如果该参数为 true,则分析这个类
返回:
得到的 Class 对象
抛出:
ClassNotFoundException - 如果无法找到类LZ你重写loadClass方法的时候,调用findLoadedClass来查找是否加载过了吗?
噢噢噢噢,我愚蠢了,我重写loadClass并没有调用父类加载器去加载,这样破坏了双亲委托机制。谢谢提醒