也許你認為Class Load是一個進階話題,不管怎樣,作為開發人員你還是要瞭解它。 本文基於最新得JDK5,然後將將訴的內容都包含了最基本的原理,希望你能更加深入瞭解自己所使用得語言。
理解CLassLoader 如果你自己定義叻一個 org.test.Object 。你在程式中這樣寫:import ort.test.ObjectObject o = new String();
也許你欣然以為這樣寫沒問題,但實際上你錯了。 這樣是不正確的,會報 ClassCastException,一個Class在JVM中得標識呢是由它得 PackAge 和 類名決定得。 也就是它得名稱空間。 org.test.Object 可不是 java.lang.Object 在java中呢,每個類都是java.lang.Class得執行個體。也就是說。
java.lang.Class klass = Myclass.class;
Myclass myclass = new Myclass() 等同於 myclass.newInstance();
在JVM中。所有得類都由 java.lang.ClassLoader.(或者是它得子類開發人員自己添加得),我們在啟動得時候都是借力於JAVA_HOME/jre/rt.jar。 不過我們發現JDK這裡並沒有任何文檔介紹bootstrap.jar。 實際上bootstrap Class Loader是JDK之外得,它得方式和JVM的是不一樣的。(本文不做介紹)
java.net.URLClassLoader
java.security.SecureClassLoader
java.rmi.server.RMIClassLoader
sun.applet.AppletClassLoader
Class Loaders工作原理
除了bootstrap之外,所有的Classloader都有個父類Class Loader ,他們都是instanceof java.lang.ClassLoader 來看看JDK1.5中的工作原理。假如有個方法loadClass protected synchronized Class<?> loadClass
(String name, boolean resolve)
throws ClassNotFoundException{
// First check if the class is already loaded
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke
// findClass to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
那麼Set它父類的方式有兩種。public class MyClassLoader extends ClassLoader{
public MyClassLoader(){
super(MyClassLoader.class.getClassLoader());
}
}或者public class MyClassLoader extends ClassLoader{
public MyClassLoader(){
super(getClass().getClassLoader());
}
} 這裡是首選第一種。 因為getClass()是在建構函式內部得方法,所以必須要有建構函式代碼存在,但是如果不存在,那就找父類得classloader 一直找啊找,直至找到到findBootstrapClass, 如果它也不存在得話,那時候findClass()方法會被調用執行。。到那時候會報一個ClassNotFoundException。 來看看findClass()得代碼 protected Class<?> findClass(String name)
throws ClassNotFoundException {
throw new ClassNotFoundException(name);
} 在findClass() 方法內 class loader要取得到得位元組碼(就是.class檔案裡得內容),然而不不一定就是.class檔案, 這些位元組碼可以來自本地,也可以是系統,網路(藉著這個你可以理解一下Cobra,RMI),也可以是用BCEL(Apache一個基於位元組碼得一個引擎庫) ...等等。 一但位元組碼找到了。那時候就開始執行defineClass()方法。那時候會定義出一個類的執行個體來。
如果有兩個ClassLoader 執行個體化兩個相同得代碼,defineClass()定義得兩個類也是不同得。詳細請看(Java language specification)
protected Class<?> findClass(String name)
throws ClassNotFoundException {
throw new ClassNotFoundException(name);
} 在findClass() 方法內 class loader要取得到得位元組碼(就是.class檔案裡得內容),然而不不一定就是.class檔案, 這些位元組碼可以來自本地,也可以是系統,網路(藉著這個你可以理解一下Cobra,RMI),也可以是用BCEL(Apache一個基於位元組碼得一個引擎庫) ...等等。 一但位元組碼找到了。那時候就開始執行defineClass()方法。那時候會定義出一個類的執行個體來。
如果有兩個ClassLoader 執行個體化兩個相同得代碼,defineClass()定義得兩個類也是不同得。詳細請看(Java language specification) 展示了一個MyMainclass.class如何裝載執行。(由多個classLoader載入同一個Target.class),----和我們想象中有差別得是,它首先是由於BootStarpClassLoader載入得。根據上面得解析,既然兩個classLoader()載入Target.class得位元組碼 ,那defineClass()就會產品兩個class得定義得。 所以很容易得出結論Target target3 = (Target) target2; 是不能被執行地。
具體請看Inside Class Loaders(Andreas Schaefer)