参考博客:
深入分析ClassLoader
在阅读文章后,对例子进行更详细的解析。
- Parent接口
public interface Parent {
public void say();
}
- Man实现类
public class Man implements Parent {
@Override
public void say() {
System.out.println("hi, I'm a boy!");
}
}
- MyClassLoader类
public class MyClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
System.out.println("my class loader find class");
byte[] bt = loadClassData(name);
return defineClass(name, bt, 0, bt.length);
}
private byte[] loadClassData(String className) {
InputStream is = getClass().getClassLoader().getResourceAsStream(className.replace(".", "/") + ".class");
ByteArrayOutputStream byteSt = new ByteArrayOutputStream();
int len = 0;
try {
while ((len = is.read()) != -1) {
byteSt.write(len);
}
} catch (IOException e) {
e.printStackTrace();
}
return byteSt.toByteArray();
}
}
- 测试类
public class Test {
public static void main(String[] args) throws Exception {
Test.test1();
System.out.println("=========================");
Test.test2();
}
private static void test1() throws Exception {
MyClassLoader loader = new MyClassLoader();
Class<?> c = loader.loadClass("Man");
System.out.println("Loaded by :" + c.getClassLoader());
System.out.println("Parent.class Loaded by :" + Parent.class.getClassLoader());
Object man = c.newInstance();
System.out.println("c.newInstance() Loaded by :" + man.getClass().getClassLoader());
System.out.println("parent instanceof Parent :" + String.valueOf(man instanceof Parent));
Parent p = (Parent) man;
System.out.println("p.getClass() Loaded by :" + p.getClass().getClassLoader());
p.say();
System.out.println("Man.class Loaded by :" + Man.class.getClassLoader());
System.out.println("man instanceof Man :" + String.valueOf(man instanceof Man));
Man m = (Man) man;
System.out.println("m.getClass() Loaded by :" + m.getClass().getClassLoader());
m.say();
}
private static void test2() throws Exception {
MyClassLoader loader = new MyClassLoader();
Class<?> c = loader.findClass("Man");
System.out.println("Loaded by :" + c.getClassLoader());
System.out.println("Parent.class Loaded by :" + Parent.class.getClassLoader());
Object man = c.newInstance();
System.out.println("c.newInstance() Loaded by :" + man.getClass().getClassLoader());
System.out.println("man instanceof Parent :" + String.valueOf(man instanceof Parent));
Parent p = (Parent) man;
System.out.println("p.getClass() Loaded by :" + p.getClass().getClassLoader());
p.say();
System.out.println("Man.class Loaded by :" + Man.class.getClassLoader());
Man m = new Man();
System.out.println("m Loaded by:" + m.getClass().getClassLoader());
System.out.println("man Loaded by :" + man.getClass().getClassLoader());
System.out.println("man instanceof Man :" + String.valueOf(man instanceof Man));
m = (Man) man;
System.out.println("m.getClass() Loaded by :" + m.getClass().getClassLoader());
m.say();
}
}
结果:
Loaded by :sun.misc.Launcher$AppClassLoader@18b4aac2
Parent.class Loaded by :sun.misc.Launcher$AppClassLoader@18b4aac2
c.newInstance() Loaded by :sun.misc.Launcher$AppClassLoader@18b4aac2
parent instanceof Parent :true
p.getClass() Loaded by :sun.misc.Launcher$AppClassLoader@18b4aac2
hi, I'm a boy!
Man.class Loaded by :sun.misc.Launcher$AppClassLoader@18b4aac2
man instanceof Man :true
m.getClass() Loaded by :sun.misc.Launcher$AppClassLoader@18b4aac2
hi, I'm a boy!
=========================
my class loader find class
Loaded by :MyClassLoader@14ae5a5
Parent.class Loaded by :sun.misc.Launcher$AppClassLoader@18b4aac2
c.newInstance() Loaded by :MyClassLoader@14ae5a5
man instanceof Parent :true
p.getClass() Loaded by :MyClassLoader@14ae5a5
hi, I'm a boy!
Man.class Loaded by :sun.misc.Launcher$AppClassLoader@18b4aac2
m Loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
man Loaded by :MyClassLoader@14ae5a5
man instanceof Man :false
Exception in thread "main" java.lang.ClassCastException: Man cannot be cast to Man
at Test.test2(Test.java:47)
at Test.main(Test.java:6)
第一个例子是自定义类加载器委托AppClassLoader
对类进行加载,第二个例子是采用自定义类加载器本身对子类进行加载。
从第二个例子可以看出,虽然子加载器和父类加载器分别加载了Man
这个类,但这两个类由于命名空间不同,所以不能相互转换。
继续来点刺激的,将parent
声明为class
,先后用类加载器加载父类和子类:
private static void test3() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
MyClassLoader loader = new MyClassLoader();
Class<?> parentClzz = loader.findClass("Parent");
Class<?> manClzz = loader.findClass("Man");
Object man = manClzz.newInstance();
Object parent = parentClzz.newInstance();
System.out.println(man instanceof Man);
System.out.println(parent instanceof Parent);
System.out.println(man instanceof Parent);
System.out.println(Man.class.getClassLoader());
System.out.println(Parent.class.getClassLoader());
System.out.println(man.getClass().getClassLoader());
System.out.println(parent.getClass().getClassLoader());
}
结果:
false
false
false
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2
MyClassLoader@7f31245a
MyClassLoader@7f31245a
换成两个类加载器,分别加载父类和子类:
private static void test4() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
MyClassLoader loader = new MyClassLoader();
MyClassLoader2 loader2 = new MyClassLoader2();
Class<?> parentClzz = loader.findClass("Parent");
Class<?> manClzz = loader2.findClass("Man");
Object man = manClzz.newInstance();
Object parent = parentClzz.newInstance();
System.out.println(man instanceof Man);
System.out.println(parent instanceof Parent);
System.out.println(man instanceof Parent);
System.out.println(Man.class.getClassLoader());
System.out.println(Parent.class.getClassLoader());
System.out.println(man.getClass().getClassLoader());
System.out.println(parent.getClass().getClassLoader());
}
结果:
false
false
true
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2
MyClassLoader2@45ee12a7
MyClassLoader@7f31245a
哦吼,是不是很刺激?