不同類加載器加載同一個class文件


不同類加載器加載同一個class文件得到的類型也是不同的。

驗證如下:

D:\\00-test目錄下,有名為Test.class的文件,其編譯前的源碼如下:

public class Test {
    public static int count = 0;

    public Test() {
        ++count;
        System.out.println(this.getClass().getClassLoader());
        System.out.println("count: " + count);
    }
}

每當創建一個對象的時候,靜態變量count就會自增,可以利用count的值來判定不同類加載器得到的Class對象是否是同一個。

創建Main類如下:

public class Main {
    public static void main(String[] args) throws Exception {
        URLClassLoader loader_1 =
                new URLClassLoader(new URL[]{new File("D:\\00-test").toURI().toURL()});

        URLClassLoader loader_2 =
                new URLClassLoader(new URL[]{new File("D:\\00-test").toURI().toURL()});

        Class<?> clazz_1 = loader_1.loadClass("Test");
        clazz_1.newInstance();
        Class<?> clazz_2 = loader_2.loadClass("Test");
        clazz_2.newInstance();
    }
}

main()方法中,首先自定義兩個類加載器,分別使用這兩個類加載器加載Test.class文件,然后使用得到的Class對象創建實例,最后得到結果如下:

java.net.URLClassLoader@1b6d3586
count: 1
java.net.URLClassLoader@74a14482
count: 1

可以看到,兩個對象的類加載器並不相同,count值卻是相同的,這說明這兩個實例雖然都是從Test.class中得來,類型卻並不相同,從而count只自增一次。

實際上,在jvms8的5.3.2節有這樣一段闡述:

At run time, a class or interface is determined not by its name alone, but by a pair:
its binary name (§4.2.1) and its defining class loader. Each such class or interface
belongs to a single run-time package. The run-time package of a class or interface is
determined by the package name and defining class loader of the class or interface.

翻譯如下:
在運行時,一個類或者接口並不是單單由它的名稱確定的,而是由它的二進制名稱以及它的定義類加載器共同確定的。
每個這樣的類或者接口都屬於一個運行時包,運行時包則由包名和定義類加載器共同確定。

上述中所謂的定義類加載器實際上就是getClassLoader()的返回值,而這個概念的產生則跟類加載過程中的“雙親委派機制”有關。

當要加載一個類時,第一個發起類加載的加載器稱之為“初始類加載器”(initiating loader),但是根據“雙親委派機制”,它會先將加載委派給父加載器,如果父加載器加載失敗,才會最終由自己嘗試加載。而無論哪個加載器加載成功,它就是該類的定義類加載器(defining class loader)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM