[英]ClassLoader in Java
我正在使用Java中的类加载器,发现以下行为。 我可以从逻辑上对此进行推理,但是我不确定我所假设的是完全正确的。 我想知道这种行为的更正式解释。
我在想什么? 所以我有以下代码:
URL[] classURLs = {new URL("file://C:/Users/HP/IdeaProjects/test/out/production/test/")};
URLClassLoader urlClassLoader = new URLClassLoader(classURLs, null);
Class<?> personClass = urlClassLoader.loadClass("com.test.Person");
// the following line will give a ClassCastException
Person p = (Person) personClass.getDeclaredConstructor().newInstance();
现在,最后一行给出了ClassCastException
。
我的理由(猜测)为什么我得到一个ClassCastException
:的类加载器personClass
是urlClassLoader
,而的类加载器Person
类实际上是应用类加载器或系统类加载器( 请纠正我,如果我错了 )。 这些类加载器不匹配,我得到了ClassCastException
。 (我在这里假设在类型转换时对类加载器执行检查)
因此,现在我继续通过以下方式探索和更改URLClassLoader
的构造:
URLClassLoader urlClassLoader = new URLClassLoader(classURLs, Main.class.getClassLoader());
Main
是封闭的类。 上面的代码使我免于ClassCastException
。
我对此的推理( 猜测 ):现在, urlClassLoader
将应用程序类加载器作为其父级(此应用程序类加载器与用于加载Person
类的加载器相同),在尝试urlClassLoader
时,Java检查类加载器是否匹配,并且此检查继续与urlClassLoader
的父级urlClassLoader
,向上一级进行类加载器匹配后,没有ClassCastException
。
我假设要与您要进行类型转换的类的类加载器进行检查,以检查要类型转换的对象的类的类加载器,如果不匹配,则尝试进行对象转换的类加载器的父级进行匹配并且这继续。
如果我在任何时候错了,请纠正我,并提供指向此行为的正式文档的指针。
我已经看到了此链接 ,但这未提供我所要求的详细信息。
您观察到的行为的正式文档在ClassLoader#loadClass()文档中:
用指定的二进制名称加载类。 此方法的默认实现按以下顺序搜索类:
调用findLoadedClass(String)以检查是否已加载该类。
在父类加载器上调用loadClass方法。 如果父级为null,则使用虚拟机内置的类加载器。
调用findClass(String)方法以查找类。
如果指定父类加载器,则URLClassLoader
在尝试加载类本身之前检查父类加载器是否包含该类,这意味着它将从您的应用程序类路径中找到该类。
因此,如果您设置父类加载器,则此行:
Class<?> personClass = urlClassLoader.loadClass("com.test.Person");
表现与
Class<?> personClass = Main.class.getClassLoader().loadClass("com.test.Person");
如果com.test.Person
类在应用程序类加载器上可用(必须为必需,否则无法加载您的Main类)。
您正在动态加载类,因此,由于您能够编译类“ Person”,这意味着您将两次加载同一类,从而导致类强制转换异常。
从类路径中删除该库,但是不会收到此错误,您也将失去对Person对象的访问。
当您加载它时,它仍然存在,但是访问它的方式是通过Reflection,并且您必须将“ Person”对象存储为“ Object”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.