Java程式設計師從笨鳥到菜鳥之(九十八)深入java虛擬機器(七)深入原始碼看java類載入器ClassLoader
歡迎閱讀本專題的其他部落格:
ClassLoader類載入器是負責載入類的物件。ClassLoader 類是一個抽象類。如果給定類的二進位制名稱(即為包名加類名的全稱),那麼類載入器會試圖查詢或生成構成類定義的資料。一般策略是將名稱轉換為某個檔名,然後從檔案系統讀取該名稱的“類檔案”。java.lang.ClassLoader類的基本職責就是根據一個指定的類的名稱,找到或者生成其對應的位元組程式碼,然後從這些位元組程式碼中定義出一個 Java 類,即 java.lang.Class類的一個例項。除此之外,ClassLoader還負責載入 Java
首先我們來看一下Classloader類的兩個構造方法。
從上邊的幫助文件中我們可以發現,在建立一個classloader的例項時我們可以顯示的指出他的父載入器,也可以不指定,不指定的時候他的預設的父載入器是系統載入器。我們來看一下原始碼的實現:
/** * Creates a new class loader using the <tt>ClassLoader</tt> returned by * the method {@link #getSystemClassLoader() * <tt>getSystemClassLoader()</tt>} as the parent class loader. */ protected ClassLoader() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkCreateClassLoader(); } this.parent = getSystemClassLoader(); initialized = true; }
/** * Creates a new class loader using the specified parent class loader for */ protected ClassLoader(ClassLoader parent) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkCreateClassLoader(); } this.parent = parent; initialized = true; }
從上面原始碼我們可以發現,classloader中一定有一個parent的屬性來指定當前loader的附加器。其原始碼也證明了我們剛才上面的說法。
看完構造方法的實現,下一步我們來看一下ClassLoader中一個特別重要的方法loadclass方法,這個方法就是用來載入類的。這個方法在jdk中有個過載的方法,但是其實是一個樣的。一個帶有是否連結類的方法,一個不帶。下面我們就看一下這個方法的原始碼:
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
/**
* Loads the class with the specified <a href="#name">binary name</a>. The
* default implementation of this method searches for classes in the
* @throws ClassNotFoundException
* If the class could not be found
*/
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been 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 in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
關於這個方法的原始碼解釋,我感覺我沒必要解釋什麼,因為在API中已經有詳細的解釋了。我在解釋肯定也不如他解釋的好,所以我們來看一下API是怎麼解釋的吧:
雖然jdk已經解釋的很清楚了,但是有一點我還是要在補充一下。從上面的原始碼我們可以看出loadClass方法是一個遞迴的方法,一直往上找,一直找到根類載入器為止,然後讓類載入器去載入這個類。至於跟載入器是怎麼實現的我們就不得而知了。因為跟類載入載入類時一個本地方法,他是用c++寫的。我們無法看到他的原始碼。這樣驗證了在前面我們所說的類載入器的父類委託機制。
下面我們來看一下findClass方法,我們在上面的程式碼中發現。在loadClass方法中有呼叫這個findclass方法,下面我們首先來看一下API對這個方法的介紹:
從上面介紹我們可以看出,這個方法主要是來查詢我們的類檔案的。我們在自定義我們自己的類載入器的時候應該重寫這個方法,因為jdk中對這個方法基本沒有實現什麼,這就需要我們自己來重寫這個方法,用我們自己的所定義的方法去查詢類檔案。不信。你可以看一下他的原始碼實現:
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
暫時先介紹這些吧。其他的方法基本都差不多,最近感覺部落格越來越難寫,越來越吃力。越來越發現底層理論的缺乏。希望通過自己的努力,可以慢慢改變這個現狀。
------------------------------------------------------------------------------------------------------------