JVM 类加载器_2

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_39161031/article/details/82812828

命名空间深度解析

直接先上例子

package com.ssy.jvm.classloader;

import java.lang.reflect.Method;

public class MyTest21 {
    public static void main(String[] args) throws Exception {
        MyFirstClassLoader loader1 = new MyFirstClassLoader("loader1");
        MyFirstClassLoader loader2 = new MyFirstClassLoader("loader2");

        loader1.setPath("/Users/ddcc/Desktop");
        loader2.setPath("/Users/ddcc/Desktop");

        Class<?> clazz1 = loader1.loadClass("com.ssy.jvm.classloader.MyPerson");
        Class<?> clazz2 = loader2.loadClass("com.ssy.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);
    }
}
package com.ssy.jvm.classloader;

public class MyPerson {
    private MyPerson myPerson;

    public void setMyPerson(Object myPerson) {
        this.myPerson = (MyPerson) myPerson;
    }
}

我们先将classpath中的MyPerson.class文件保留

结果:

true

解析:

    经过上一节类加载器的讲解,我们知道,类加载的过程是通过双亲委托机制来完成的。loader1和loader2都会交由它的父加载器–系统类加载器 去进行加载,而很明显,系统类加载器可以加载MyPerson类。当loader1交由系统类加载器加载后,loader2再交由系统类加载器加载时,发现这个类已经被加载了,那么会直接返回这个类的Class对象,所以结果为True。

我们现在将classpath中的MyPerson.class删除,在Desktop上放这个文件。

结果

findClass invoked: com.ssy.jvm.classloader.MyPerson
class loader name: loader1
findClass invoked: com.ssy.jvm.classloader.MyPerson
class loader name: 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.ssy.jvm.classloader.MyTest21.main(MyTest21.java:22)
Caused by: java.lang.ClassCastException: com.ssy.jvm.classloader.MyPerson cannot be cast to com.ssy.jvm.classloader.MyPerson
	at com.ssy.jvm.classloader.MyPerson.setMyPerson(MyPerson.java:7)
	... 5 more

分析

    这个结果就非常好玩了。首先打印出false,其次,抛出了异常。我们分别来解释。
    loader1和loader2是没有直接或间接父子关系的两个加载器。所以它们在各自的命名空间内。

同一个命名空间内的类是相互可见的
子加载器的命名空间包含父加载器的命名空间,因此子加载器加载的类能看到父加载器所加载的类
父加载器所加载的类看不到子加载器所加载的类。
如果两个加载器之间没有直接或者间接的父子关系,那么相互不可见

    所以loader1加载的Class对象和loader2加载的Class对象是相互不可见的。由此,它们new出来的对象也是相互不可见的。当用反射调用方法将loader2加载的Class对象所对应的类的实例传入时,转换为loader1加载的Class对象所对应的类中,就会抛出类转换异常

    单独看java.lang.ClassCastException: com.ssy.jvm.classloader.MyPerson cannot be cast to com.ssy.jvm.classloader.MyPerson这个异常的时候,真的是不知所云,哈哈哈。。

猜你喜欢

转载自blog.csdn.net/weixin_39161031/article/details/82812828