jvm原理(17)类加载器命名空间深度解析与实例分析

本文探讨了两个不同类加载器加载同一类时的行为差异,分析了类加载器的命名空间概念及其对类可见性的影响,并通过具体示例展示了如何通过反射调用不同命名空间内的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们在 上一节讲到实例基础上做一下改动:

public class MyTest21 {
    public static void main(String[] args)  throws Exception{
        MyTest16 loader1 = new MyTest16("loader1") ;
        MyTest16 loader2 = new MyTest16("loader2") ;
        loader1.setPath("E:\\data\\classes\\");
        loader2.setPath("E:\\data\\classes\\");
        Class<?> clazz1 = loader1.loadClass("com.twodragonlake.jvm.classloader.MyPerson");
        Class<?> clazz2 = loader2.loadClass("com.twodragonlake.jvm.classloader.MyPerson");
        System.out.println(clazz1 ==  clazz2);
        Object object1 = clazz1.newInstance();
        Object object2 = clazz2.newInstance();

        Method method   = clazz1.getMethod("setMyPerson",Object.class);
        method.invoke(object1,object2);
    }
}

即指定了loader1和loader2的path路径,然后我们重新编译当前工程,将com.twodragonlake.jvm.classloader.MyPerson的class文件复制一份到【E:\data\classes\】下边,然后删除当前工程的MyPerson的class文件,然后运行MyTest21 的main函数,打印 结果会是什么呢?

findClass invoked com.twodragonlake.jvm.classloader.MyPerson
 this.classLoaderName : loader1
findClass invoked com.twodragonlake.jvm.classloader.MyPerson
 this.classLoaderName : loader2
false
Exception in thread "main" java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.twodragonlake.jvm.classloader.MyTest21.main(MyTest21.java:18)
Caused by: java.lang.ClassCastException: com.twodragonlake.jvm.classloader.MyPerson cannot be cast to com.twodragonlake.jvm.classloader.MyPerson
    at com.twodragonlake.jvm.classloader.MyPerson.setMyPerson(MyPerson.java:6)
    ... 5 more

分析:首先loader1和loader2虽然都是MyTest16的对象,但是他们之间在类加载的层次上没有任何的关系,loader1加载MyPerson的时候通过向上委托一直到启动类加载器然后又往下到应用类加载器都无法加载,只能通过loader1加载器来加载,loader1加载的MyPerson的class对象clazz1属于loader1的命名空间,同样的道理clazz2属于loader2的命名空间,clazz1和clazz2是不同的2个class对象,所以我们在通过反射调用clazz1的实体object1的setMyPerson方法的时候,传入的是clazz2的实体对象,clazz2和clazz1属于不同的命名空间,相互之间不可见,在强制向下转型的时候肯定是抛出转型失败的错误。
这里写图片描述
这里写图片描述
子加载器加载的类可以看到父加载器加载的类;
父加载器加载的类无法看到子加载器加载的类;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值