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,導致報錯。
結論:
關於命名空間
- 子類加載器可以訪問父類加載器所加載的類
- 父類加載器無法訪問到子類加載器所加載的類
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"));
}
}
結果: