美文网首页JAVA
ClassLoader-父子类转换

ClassLoader-父子类转换

作者: YDDMAX_Y | 来源:发表于2018-12-17 21:05 被阅读0次

父类=子类能转换的条件为:

  1. 子类的类加载器==父类的类加载器
    or
  2. 父类的类加载器是子类的类加载器的parent(不要求直接parent)

类由class文件+ClassLoader唯一确定

首先,运行时刻** 类是由class文件 + 类加载器唯一确定的 **。即同一个class文件如果加载器不一样,运行时也是两个不同的类,测试代码如下:

public static void main(String[] args) throws Exception {
        URL[] urls = new URL[] {new URL("file:/Temp/")};
        ClassLoader cl1 = new URLClassLoader(urls, null);
        ClassLoader cl2 = new URLClassLoader(urls, null);

        Class clz1 = cl1.loadClass("Test");
        Class clz2 = cl2.loadClass("Test");

        System.out.println(clz2.isAssignableFrom(clz1));
}

测试结果是:false

问题

由于类是由class文件 + 类加载器唯一确定的, 所以下面这段代码是会抛cast异常的:

public static void main(String[] args) throws Exception {
        URL[] urls = new URL[] {new URL("file:/Temp/")};
        ClassLoader cl = new URLClassLoader(urls, null);

        Class clz = cl.loadClass("Test");
        System.out.println("1:" + Test.class.getClassLoader());
        System.out.println("2:" + clz.getClassLoader());
        Test test = (Test)clz.newInstance();
}

输出如下:

1:sun.misc.Launcher$AppClassLoader@18b4aac2
2:java.net.URLClassLoader@60e53b93

Exception in thread "main" java.lang.ClassCastException: Test cannot be cast to Test
    at ClassLoaderTest3.main(ClassLoaderTest3.java:15)

由于Test是由AppClassLoader加载的,但是clz是由URLClassLoader加载的,从而会出现ClassCastException。
我们把上面代码稍微改一下:TestInterface作为接口,有一个实现类:TestImpl。是否能进行向上转型呢?
测试代码如下:

public static void main(String[] args) throws Exception {
        URL[] urls = new URL[] {new URL("file:/Temp/")};
        ClassLoader cl = new URLClassLoader(urls);

        Class clz = cl.loadClass("TestImpl");

        System.out.println("1:" + TestInterface.class.getClassLoader());
        System.out.println("2:" + clz.getClassLoader());

        TestInterface test = (TestInterface)clz.newInstance();
}

输出如下:

1:sun.misc.Launcher$AppClassLoader@18b4aac2
2:java.net.URLClassLoader@60e53b93

Process finished with exit code 0

TestInterface是由AppClassLoader加载的,clz是由URLClassLoader加载的,但,居然能够正常的向上转型!我期待的异常居然没抛!

分析

细心的人可能已经发现了,这两个比对的测试样例生成ClassLoader的地方不一样。
第一个例子:

ClassLoader cl = new URLClassLoader(urls, null);

第二个例子:

ClassLoader cl = new URLClassLoader(urls);

这里URLClassLoader的构造方法如下:

public URLClassLoader(URL[] urls, ClassLoader parent) 

如果不传第二个参数,默认使用上下文类加载器作为parent,即AppClassLoader作为parent加载器。
双亲委派协议这里就不具体说了,太多相关文章了。
接下来,我们分析一下第二个测试用例:

public class TestImpl implements TestInterface

在使用URLClassLoader加载TestImpl时,由于TestImpl实现了TestInterface,会先去加载TestInterface,在加载TestInterface时,由于双亲委派协议,TestInterface加载时,会委托使用URLClassLoader的父加载器AppClassLoader进行加载,恰好AppClassLoader可以进行加载,从而TestImpl是通过AppClassLoader加载的,TestInterface是通过URLClassLoader加载的。
最后,下面代码的左边TestInterface和clz的接口TestInterface都是由URLClassLoader加载的,从而没有转型问题。

TestInterface test = (TestInterface)clz.newInstance();

总结一下,父子关系是和类加载器没有关系的,类型是由class文件和类加载器唯一确定的。搞清楚最基本的概念非常重要,不要混淆了。

相关文章

  • ClassLoader-父子类转换

    父类=子类能转换的条件为: 子类的类加载器==父类的类加载器or 父类的类加载器是子类的类加载器的parent(不...

  • C++之数据类型转换

    上下行转换 子类上行转换成父类 父类下行转换成子类 静态转换(static_cast) 动态转换(dynamic_...

  • 里氏转换

    里氏转换, 1子类可以赋值给父类。2如果父类中装的是子类对象,可以将这个父类强转换成子类。看看这个例子就能懂。 }

  • C#面向对象基础2

    1.里氏转换: 子类可以赋值给父类 如果父类创建的是子类对象,那么可以将父类强制转换为子类 Is可以判断一个类的对...

  • java基础_面向对象—多态

    向上转型(自动类型转换)【之类转换成父类型】 向下转型(强制类型转换)【父类转换成子类型】

  • 里氏转换

    里氏转换的特点 父类引用指向子类对象 如果父类引用指向的是子类对象,那么可以将这个父类强转为子类对象 将父类强转为...

  • 多态

    向上转型,隐式转换,自动转型 父类引用指向子类,可以调用子类重写父类方法,及父类派生的方法,但无法调用子类特有的方...

  • .Net基础10

    1、里氏转换 1)、子类可以赋值给父类2)、如果父类中装的是子类对象,那么可以讲这个父类强转为子类对象 2、类型转...

  • 里氏转换

    里氏转换的原则:1、子类可以直接赋值给父类。父类若指向子类,那么可以强制转化为该子类。 例如 static voi...

  • C#基础第十天(面向对象)

    1、里氏转换 1.子类可以赋值给父类 2.如果父类中装的是子类的对象,那么可以将这个父类强转为子类对象。 2、 子...

网友评论

    本文标题:ClassLoader-父子类转换

    本文链接:https://www.haomeiwen.com/subject/hvchkqtx.html