【JVM】深入理解类加载器--类命名空间详解(三)

8 篇文章 0 订阅

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

结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值