1、ClassLoader(類加載器)的做用java
若是一個程序包含不止一個class文件,那麼當程序啓動時,帶有main方法的類的class文件做爲程序入口先被JVM加載,而後根據程序調用的須要,再逐步進行其餘class文件的加載。ClassLoader的做用就是動態的加載class文件。算法
加載的結果:bootstrap
在加載class文件以後,會在方法區中生成「類信息的二進制數據」,包含靜態變量、靜態方法、常量池和類的代碼,同時在堆中生成一個Class對象,此對象表明這個「二進制數據」。api
2、Java默認的三個ClassLoader網絡
1.Bootstrap ClassLoader 啓動類加載器,是java類加載器中最頂層的類加載器,負責加載JDK中的核心類庫,可經過如下代碼獲取該類加載器加載了哪些相關jar或class文件:jvm
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs(); 測試
for (int i = 0; i < urls.length; i++) { url
System.out.println(urls[i].toExternalForm()); spa
}orm
也能夠經過如下代碼:
System.out.println(System.getProperty(「sun.boot.class.path"));
ps:(bootstrap ClassLoader不是繼承自此,是C++進行編寫的,嵌到了JVM內核)。
2.Extension ClassLoader:擴展類加載器,負責加載jre/lib/ext/目錄下的全部jar。
3.App ClassLoader:系統應用類加載器,主要負責加載應用程序classpath目錄下的全部jar和class文件。
3、雙親委託機制:
在加載類的過程當中,Bootstrap先進行加載,若是沒有加載到,則extension再進行加載,若是仍是沒有加載到,再交給App加載。避免了用戶定義String等核心api中的類。若是同一個name的class文件,不是由同一個ClassLoader加載的,JVM也會認爲這是兩個不一樣的class文件。
經過如下代碼打印出全部的類加載器:
ClassLoader classloader= c1.getClassLoader();
while(classloader!=null){
System.out.println(classloader);
classloader = classloader.getParent();
}
System.out.println(classloader);
自定義加載器
除了這三個類加載器,用戶能夠自定義本身的類加載器。既然JVM已經提供了默認的類加載器,爲何還要定義自已的類加載器呢?
由於Java中提供的默認ClassLoader,只加載指定目錄下的jar和class,若是咱們想加載其它位置的類或jar時,好比:我要加載網絡上的一個class文件,經過動態加載到內存以後,要調用這個類中的方法實現個人業務邏輯。在這樣的狀況下,默認的ClassLoader就不能知足咱們的需求了,因此須要定義本身的ClassLoader。
如何自定義類加載器:
一、繼承java.lang.ClassLoader
二、重寫父類的findClass方法
父類有那麼多方法,爲何恰恰只重寫findClass方法?
由於JDK已經在loadClass方法中幫咱們實現了ClassLoader搜索類的算法,當在loadClass方法中搜索不到類時,loadClass方法就會調用findClass方法來搜索類,因此咱們只需重寫該方法便可。如沒有特殊的要求,通常不建議重寫loadClass搜索類的算法。
小測試1:
將ClassLoaderTest.class打包成ClassLoaderTest.jar,放到Extension ClassLoader的加載目錄下(JAVA_HOME/jre/lib/ext),再運行代碼,會發現。。。是由ext加載的。
小測試2:
用Bootstrcp ClassLoader來加載ClassLoaderTest.class,有兩種方式:
一、在jvm中添加-Xbootclasspath參數,指定Bootstrcp ClassLoader加載類的路徑,並追加咱們自已的jar(ClassTestLoader.jar)
二、將class文件放到JAVA_HOME/jre/classes/目錄下(上面有提到)