【JVM】深入理解類加載器--類命名空間詳解(三)

1 類命名空間

每個類加載器有自己的命名空間,由該類加載器所有的父類加載器和所加載的類組成。
同一個命名空間不會存在類完整名字(包括包名)相同的兩個類 。
但是不同的命名空間可以。

2 代碼示例

PS,這裏使用之前定義過的自定義類加載器。點這裏查看

首先新建兩個用於測試的類

public class MyCat {
    public MyCat(){
        System.out.println("MyCat is loaded by:"+ this.getClass().getClassLoader());
    }
}
public class MySample {
    public MySample(){
        System.out.println("MySample is loaded by:"+ this.getClass().getClassLoader());
        new MyCat();
    }
}
package com.cj.jvm.classloader;

public class MyTest13 {
    public static void main(String[] args) throws Exception{
        MyTest12 loader1 = new MyTest12("loader1");
        Class<?> clazz = loader1.loadClass("com.cj.jvm.classloader.MySample");
        System.out.println("Class : "+ clazz.hashCode());

        // 註釋掉之後MyCat可能不會被加載
        Object object = clazz.newInstance();
    }
}

結果:
在這裏插入圖片描述
分析:
loader1去加載MySample類,首先委託其父加載器,系統類加載器。由於MySample.class在當前類加載器中,所有MySample由系統類加載器加載。

在實例化MySample的過程中,構造函數中包含new MyCat(),所以需要加載MyCat類,由於雙親委託,同理,由系統類加載器加載。


接下來我們對代碼做一點修改。在當前的classpath下刪除MyCat.class,保留MySample.class。

public class MyTest13_1 {
    public static void main(String[] args) throws Exception{
        MyTest12 loader1 = new MyTest12("loader1");
        loader1.setPath("C:\\Users\\CJ\\Desktop\\");

        Class<?> clazz = loader1.loadClass("com.cj.jvm.classloader.MySample");
        System.out.println("Class : "+ clazz.hashCode());
        
        Object object = clazz.newInstance();
    }
}

結果:
在這裏插入圖片描述
分析:
由於雙親委託,MySample被系統類加載器加載。然後在初始化時候需要加載MyCat,此時系統類加載器在當前classpath路徑下尋找不到MyCat.class,所以拋出異常。

ps:由於MySample是被系統類加載器去加載的。MyCat的初始化在MySample裏面,所以MyCat也會由系統類加載器去加載


對MyCat類進行稍微的修改,

public class MyCat {
    public MyCat(){
        System.out.println("MyCat is loaded by:"+ this.getClass().getClassLoader());
        System.out.println("from MyCat: " + MySample.class );
    }
}

然後刪除MySample.class,保留MyCat.class。運行程序
在這裏插入圖片描述
分析:
由於MySample不在當前classpath路徑下,所以MySample由自定義類加載器加載。MyCat在classpath路徑下,由於雙親委託,由系統類加載器加載。
在這裏插入圖片描述
然而,該語句導致了異常的出現。因爲系統類加載器是loader1的父加載器。父加載器加載了MyCat卻沒有加載MySample(loader1加載),MySample對其不可見。

所以在MyCat類中調用MySample.class,導致報錯。

結論:
關於命名空間

  1. 子類加載器可以訪問父類加載器所加載的類
  2. 父類加載器無法訪問到子類加載器所加載的類

3 查看Java中類加載器的加載目錄

package com.cj.jvm.classloader;

public class MyTest14 {
    //打印出各個類加載器是從什麼路徑加載的class文件
    public static void main(String[] args) {
        System.out.println(System.getProperty("sun.boot.class.path"));
        System.out.println(System.getProperty("java.ext.dirs"));
        System.out.println(System.getProperty("java.class.path"));
    }
}

結果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章