2021-05-05
在 Java 中,所有的程序都是通過 "*.class" 字節(jié)碼的文件進行存儲的,這樣在 JDK 執(zhí)行類的時候每個類都會存在一個相應(yīng)的類加載器;如果想獲得這些類加載器,直接依據(jù) Class 類即可,在 Class 類中提供如下一個重要方法:
public ClassLoader getClassLoader()
由于在 JVM 中所需要進行加載的類比較多,所以對于 ClassLoader 來講為了安全的設(shè)計起見,往往會存在由若干個父 ClassLoader ,如果要想獲得這些 ClassLoader 的信息,則可以利用 ClassLoader 類中提供的如下方法來完成:
public final ClassLoader getParent()
如果按照遞歸的處理形式來講,可以持續(xù)使用如上的方式來獲得程序里面所使用的全部的類加載器的信息。
觀察 String 類的 ClassLoader
public class StringClassLoader {
public static void main(String[] args) {
String message = "JadeBamboo";
System.out.println(message.getClass().getClassLoader());
}
}
輸出:
null
雖然此時通過代碼執(zhí)行后發(fā)現(xiàn),String 類的 ClassLoader 是一個 null,主要的原因是這個 null 是由 JVM 來實現(xiàn)的類加載器,我們的程序時無法得到這個類加載器的。
觀察自定義類的類加載器
class Book {}
public class SelfClassLoader {
public static void main(String[] args) {
Class<?> cla = Book.class;
System.out.println(cla.getClassLoader());
System.out.println(cla.getClassLoader().getParent());
System.out.println(cla.getClassLoader().getParent().getParent()); // Bootstrap
}
}
輸出:
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@677327b6
null
現(xiàn)在的 ClassLoader 一共有如下幾個:
Bootstrap:此為 JVM 系統(tǒng)內(nèi)部所提供的類加載器的處理機制,JVM 原生提供的類加載機制,專門用于加載系統(tǒng)類;
-
PlatformClassLoader:平臺類的加載器,在JDK 1.8 及以前的版本里面為 "ExtClassLoader";
在JDK 1.8 及以前的所有 JDK 里面為了方便進行第三方程序組件的擴展,會提供一個專屬的 ext 目錄(
D:\Software\Java\JDK\jre\lib\ext)。 AppClassLoader:應(yīng)用程序類加載器,用戶自己定義類的加載器
之所以在 Java 設(shè)計范疇里面為 JVM 設(shè)計不同層次的類加載器,主要的原因在于要實現(xiàn)"雙親加載"。為了提供類加載器的安全級別,在 Java 中對于所有的系統(tǒng)類使用系統(tǒng)類的加載器,如果是用戶自定義的類使用自定義類的加載器,這樣的目的時為了防止類重名的時候所造成的困擾,例如,現(xiàn)在某個惡意的用戶定義了一個 "java.lang.String" 類,如果這個類里面存在許多惡意的程序代碼,那么在用戶不知情的情況下使用了這個類,并且加載了惡意代碼就會導(dǎo)致程序的安全性的問題,那么為了解決這一點,才使用不同的加載器。用戶自定義的 String 類和系統(tǒng)中的 String 類所進行加載的時候采用的加載器是有區(qū)別的,所以才能夠保證程序類的加載正確,所謂的雙親就是防止惡意程序與系統(tǒng)類重名所造成的惡意加載。