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"));
}
}
结果: