參考博客:
深入分析ClassLoader
在閱讀文章後,對例子進行更詳細的解析。
- Parend接口
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("testJvm.Man");
System.out.println("Loaded by :" + c.getClassLoader());
Parent p;
System.out.println("Parent.class Loaded by :" + Parent.class.getClassLoader());
Object parent = c.newInstance();
System.out.println("c.newInstance() Loaded by :" + parent.getClass().getClassLoader());
System.out.println("parent instanceof Parent :" + String.valueOf(parent instanceof Parent));
p = (Parent) parent;
System.out.println("p.getClass() Loaded by :" + p.getClass().getClassLoader());
p.say();
Man m;
System.out.println("Man.class Loaded by :" + Man.class.getClassLoader());
Object man = c.newInstance();
System.out.println("c.newInstance() 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();
}
private static void test2() throws Exception {
MyClassLoader loader = new MyClassLoader();
Class<?> c = loader.findClass("testJvm.Man");
System.out.println("Loaded by :" + c.getClassLoader());
Parent p;
System.out.println("Parent.class Loaded by :" + Parent.class.getClassLoader());
Object parent = c.newInstance();
System.out.println("c.newInstance() Loaded by :" + parent.getClass().getClassLoader());
System.out.println("parent instanceof Parent :" + String.valueOf(parent instanceof Parent));
p = (Parent) parent;
System.out.println("p.getClass() Loaded by :" + p.getClass().getClassLoader());
p.say();
Man m;
System.out.println("Man.class Loaded by :" + Man.class.getClassLoader());
Object man = c.newInstance();
System.out.println("c.newInstance() 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
c.newInstance() 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 :testJvm.MyClassLoader@5680a178
Parent.class Loaded by :sun.misc.Launcher$AppClassLoader@18b4aac2
c.newInstance() Loaded by :testJvm.MyClassLoader@5680a178
parent instanceof Parent :true
p.getClass() Loaded by :testJvm.MyClassLoader@5680a178
hi, I'm a boy!
Man.class Loaded by :sun.misc.Launcher$AppClassLoader@18b4aac2
c.newInstance() Loaded by :testJvm.MyClassLoader@5680a178
man instanceof Man :false
Exception in thread "main" java.lang.ClassCastException: testJvm.Man cannot be cast to testJvm.Man
at testJvm.Test.test2(Test.java:54)
at testJvm.Test.main(Test.java:8)
第一個例子是自定義類加載器委託AppClassLoader
對類進行加載,第二個例子是採用自定義類加載器本身對子類進行加載。
從第二個例子可以看出,雖然子加載器和父類加載器分別加載了Man
這個類,但這兩個類由於命名空間不同,所以不能相互轉換。