gpt4 book ai didi

java - 无法使用 URLClassLoader 和反射转换为接口(interface)类

转载 作者:行者123 更新时间:2023-12-02 11:06:14 29 4
gpt4 key购买 nike

我有一个 jar :

/home/cole/lib/a.jar

在这个 jar 中,我有以下接口(interface)/类(可怕的名称仅用于说明目的!):

  • CreatorInterface.java
  • Base.java(实现 CreatorInterface.java)
  • AbstractBase.java(扩展 Base.java)
  • Implementation.java(扩展 AbstractBase.java)

在一个单独的项目中,我有以下代码:

final URL[] jars = new URL[] {
new File("/home/cole/lib/a.jar").toURL();
}

final URLClassLoader classLoader = new URLClassLoader(jars, null);
final Class<?> implementation = classLoader.loadClass("Implementation");
final CreatorInterface object = (CreatorInterface)implementation.newInstance();

但是,当我运行上面的代码时,我得到以下结果:

java.lang.ClassCastException:实现无法转换为 CreatorInterface

鉴于Implementation最终是实现CreatorInterface的类的实例,为什么我会收到ClassCastException

更新1

这不是关于使用URLClassLoader的问题,发现类没问题,问题似乎出在实例化中。例如,以下代码可以正常工作:

final Object object = implementation.newInstance();

更新2

正如 @davidxxx 回答的那样,我有两次接口(interface)类(一次在 jar 中,一次在使用它的项目中)。尽管界面相同,但这就是问题的原因。

但是为了使其工作,我需要像这样修复我的 URLClassLoader,以避免 ClassNotFoundException:

final ClassLoader parent = this.getClass().getClassLoader();
final URLClassLoader classLoader = new URLClassLoader(jars, parent);

最佳答案

此异常:

java.lang.ClassCastException: Implementation cannot be cast to CreatorInterface

让我认为您很可能有两个不同的 CreatorInterface 类:一个包含在 jar 中,另一个来自尝试加载它的客户端程序。
即使这两个类具有相同的名称(限定名称),对于每个类加载器来说,它们也是不同的类,因为这里您使用两个不关联的类加载器。
您拥有您运行的程序的当前类加载器以及您指定 null 作为父类加载器的另一个类加载器:

final URLClassLoader classLoader = new URLClassLoader(jars, null);

因此,当您尝试将反射创建的对象分配给 CreatorInterface 变量时,转换会失败,因为每个类加载器加载并使用了两个不同的 CreatorInterface :一个来自客户端代码的类加载器,另一个来自实例化的类加载器。
使用单个类加载器可以解决该问题,但最佳实践是将 jar 包含在项目的类路径中,并确保 jar 中提供的类的单一版本。

为了解耦,您可能应该将 jar 分成 2 个 jar:一个仅包含接口(interface)的 API jar 和一个依赖于 API jar 并包含其他类的实现 jar。
在客户端代码中,仅在类路径中添加 API jar,以便能够分配给具有接口(interface)声明类型的变量。

<小时/>

关于你的第二点:

This isn't a question about using URLClassLoader, the class is found ok, the problem appears to be in the instantiation. For example, the following code works fine:

final Object object = implementation.newInstance();

在这种情况下,您不引用接口(interface)类型。
您确实将 Implementation 对象分配给 Object,而不是分配给 CreatorInterface 变量。
正确/一致的接口(interface)和子类由类加载器加载,但在这里您永远不会有机会引发 ClassCastException,因为您永远不会将其分配给重复类的类型,而是 Object > 这是一次定义的。
所以之前遇到的问题就不会出现。

<小时/>

关于第三点:

However to make it work, I needed to fix my URLClassLoader like this, to avoid a ClassNotFoundException:

final ClassLoader parent = this.getClass().getClassLoader();
final URLClassLoader classLoader = new URLClassLoader(jars, parent);

它之所以有效,是因为您在这里创建了一个与父类加载器关联的类加载器。

事实上,如果你这样做了:

final URLClassLoader classLoader = new URLClassLoader(jars);

它将产生与创建的 URLClassLoader 对象相同的结果,默认情况下将使用对父类加载器(此处为启动应用程序的类加载器)的委托(delegate)。

关于java - 无法使用 URLClassLoader 和反射转换为接口(interface)类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50934610/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com