類加載器就是尋找類或接口字節(jié)碼文件進行解析并構(gòu)造JVM內(nèi)部對象表示的組件。在Java中,類轉(zhuǎn)載器把一個類裝入JVM中,需要經(jīng)過以下步驟:
1.裝載:查找和導(dǎo)入Class文件;
2.鏈接: 執(zhí)行校驗、準(zhǔn)備和解析步驟,其中解析步驟是可以選擇的:
a)校驗: 檢查載入Class文件數(shù)據(jù)的正確性;
b)準(zhǔn)備:給類的靜態(tài)變量分配存儲空間;
c)解析:將符號引用變成直接引用sat答案
3.初始化:對類的靜態(tài)變量、靜態(tài)代碼塊進行初始化工作。
類裝載工作是由ClassLoader及其之類負責(zé)的,ClassLoader是一個重要的Java運行時系統(tǒng)組件,它負責(zé)在運行時查找和裝入Class字節(jié)文件。JVM在運行時會產(chǎn)生三個ClassLoader:跟裝載器、ExtClassLoader(擴展類裝載器)和AppClassLoader(系統(tǒng)類裝載器)。其中,跟裝載器不是ClassLoader的子類,它使用C++編寫,因此我們在Java中看不到它,跟裝載器負責(zé)裝載JRE的核心類庫,如rt.jar,charsets.jar等。ExtClassLoader和AppClassLoader都是ClassLoader的子類。其中ExtClassLoader負責(zé)裝載JRE擴展目錄ext中的JAR類包;AppClassLoader負責(zé)裝載ClassPath路徑下的類包托福答案
這三個類裝載器之間存在父子層級關(guān)系,跟裝載器是ExtClassLoader的父裝載器,ExtClassLoader是AppClassLoader的父裝載器。默認情況下,使用AppClassLoader裝載應(yīng)用程序的類,我們可以試驗如下:
[java]
package com.uestc.test;
public class ClassLoaderTest {
public static void main(String[] args) {
ClassLoader c=Thread.currentThread()。getContextClassLoader();
System.out.println(c);
System.out.println(c.getParent());
System.out.println(c.getParent()。getParent());
}
}
運行結(jié)果如下:
[java]
sun.misc.Launcher$AppClassLoader@1016632
sun.misc.Launcher$ExtClassLoader@dc6a77
null
從上述結(jié)果可以分析得出當(dāng)前的ClassLoader是AppClassloader,父ClassLoader是ExtClassLoader,祖父ClassLoader是根類裝載器,因為在Java中無法獲得它的句柄,因此返回null.
ClassLoader與Class.forName的區(qū)別
classLoader中的函數(shù)loadclass用于Class文件的加載但并沒有完成初始化工作,而使用Class.forName則完成了初始化工作即完成對類的靜態(tài)變量、靜態(tài)代碼塊執(zhí)行初始化工作。實例如下:
需要加載的類Reflect.java如下:
[java]
package com.uestc.test;
public class Reflect {
private int userName;
private int password;
static {
System.out.println("Reflect static block");
}
public Reflect(){
System.out.println("Reflect constructs");
}
public int getUserName() {
return userName;
}
public void setUserName(int userName) {
this.userName = userName;
}
public int getPassword() {
return password;
}
public void setPassword(int password) {
this.password = password;
}
}
測試類Test.java如下:
[java]
package com.uestc.test;
public class Test {
public static void main(String[] args) {
ClassLoader classLoader=Thread.currentThread()。getContextClassLoader();
try {
System.out.println("使用ClassLoader中的loadClass加載:");
classLoader.loadClass("com.uestc.test.Reflect");
System.out.println("使用Class.forName()加載:");
Class.forName("com.uestc.test.Reflect");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
運行結(jié)果如下:
[java]
使用ClassLoader中的loadClass加載:
使用Class.forName()加載:
Reflect static block
從上述結(jié)果可以看出loadClass并沒有進行初始化工作,而Class.forName()進行了初始化工作。