在類加載過程的加載階段,有一個通過類的全限定名擷取描述類的二進制流的動作,Java虛拟機設計團隊有意将這個動作的實作放到虛拟機之外實作,以便讓使用者自己決定如何擷取所需類,這個動作的實作被稱為類加載器。
在類加載過程的加載階段,有一個通過類的全限定名擷取描述類的二進制流的動作,Java虛拟機設計團隊有意将這個動作的實作放到虛拟機之外實作,以便讓使用者自己決定如何擷取所需類,這個動作的實作被稱為類加載器。JVM根據職能的不同,設計了以下四種類加載器:
1、引導類加載器(BootStrap ClassLoader)
2、擴充類加載器(Extension ClassLoader)
3、應用程式類加載器(Application ClassLoader)
4、自定義類加載器(User ClassLoader)
前三種是虛拟機自帶的類加載器,自定義類加載器是使用者根據自己的需求設計的類加載器,下圖是四種類加載器之間的關系,圖中所表示的層次關系,并非類的繼承關系,而是描述類加載器協作關系,通常這個協作關系通過組合的方式實作(設計模式中的組合,通過組合複用父類加載器的代碼,除了引導類加載器,其他類加載器都有父類加載器),這個協作動作的實作被稱為"雙親委派模型",後面的篇章中單獨講。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5iN1EDNxEGO0Y2MzIzM0kjNxYzX5EDMwcTM1EzLcBTMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL4M3Lc9CX6MHc0RHaiojIsJye.png)
在Java程式中可按照如下代碼擷取除引導類加載器外的各個類加載器。
引導類加載器是由C/C++語言實作,嵌套在虛拟機内部,用來加載java核心庫中的類,特性如下:
1、隻加載JAVA_HOME/jre/lib/rt.jar、resources.jar或sun.boot.class.path路徑下的内容
2、加載擴充類和應用程式類類加載器,并且是它們的父類加載器,不繼承ClassLoader類,其本身沒有父類加載器。
3、出于安全考慮,隻加載包名為java、javax、sun開頭的類,
4、引導類加載器無法通過getClassLoader()方法擷取,隻會傳回null,如String.class.getClassLoader()。
擴充類加載器是Java語言實作的類加載器,在sun.misc.Launcher.ExtClassLoader中實作,派生于ClassLoader類,特性:
1、本身先有引導類加載器加載,父類加載器為引導類加載器(非繼承關系)。
2、加載java.ext.dirs系統屬性所指定的目錄中的類庫,或者加載JDK安裝目錄的jre/ext/dir擴充目錄下的類庫,使用者可以将自己的jar放入該目錄,通過擴充類加載器加載。
應用程式類加載器也是Java語言實作的類加載器,在sun.misc.Launcher.AppClassLoader中實作,派生于ClassLoader類,特性:
1、本身先有引導類加載器加載,父類加載器為擴充類加載器(非繼承關系)。
2、加載環境變量classpath或者java.class.path屬性指定的目錄下的類庫。
3、程式中預設的類加載器,一般的Java應用程式都由它加載,可以通過java.lang.ClassLoader#getSystemClassLoader方法擷取。
對于某一些特殊的類加載需求,使用者可以通過繼承ClassLoader實作自定義的類加載器,通過自定義類加載器,可以在以下的需求場景使用:
1、隔離類,如類路徑沖突。
2、防反編譯加密Class檔案。
3、擴充類的加載源。
自定義實作類加載器可以通過繼承java.lang.ClassLoader并重寫loadClas()方法或者實作findClass()(推薦)方法,如下代碼就是加載指定目錄class的簡單實作。
在虛拟機中,每個類的唯一性,由類和類加載器兩個因素決定,也就是即使同一個類被不同類加載器加載,也會導緻這兩個類不相同。在上篇文章說過,類加載完成以後會在堆區生成一個類的java.lang.Class對象作為外部接口通路方法區對應的類資訊,這個操作具象化就是Object的getClass()方法。getClass()擷取到類的Class對象,進而根據getClassLoader()方法擷取類加載器,下面代碼中自定義了類加載器MyClassLoader,在main中通過自定義類加載器加載一次ClassLoaderUniqueTest類并建立執行個體,同時在執行main方法時,虛拟機會通過應用程式類加載器加載一次ClassLoaderUniqueTest類,最後通過instanceof比較類型,這個比較類型并不限于instanceof,還可以用equals。
執行結果