无法强制转换为已实现的接口

2022-09-01 02:02:28

我很困惑...

我有一个直接实现接口的类:

public class Device implements AutocompleteResult
{...}

这里有证据证明我正在研究正确的变量:

Object match = ...;
log.debug(match.getClass()); // Outputs 'Device'
log.debug(match.getClass().getInterfaces()[0]); // Outputs 'AutocompleteResult'

然而,当我尝试将类的实例转换为接口时:

AutocompleteResult result = (AutocompleteResult) match;

我得到了一个ClassCastException!

ClassCastException: Device cannot be cast to AutocompleteResult

另外,返回 false,我不确定为什么:isAssignableFrom

log.debug(AutocompleteResult.class.isAssignableFrom(Device.class));

文档

确定此 Class 对象所表示的类或接口是否与指定的 Class 参数所表示的类或接口相同,或者是否是其超类或超接口。

难道我不应该总是能够将对象强制转换为其类实现的接口吗?

谢谢。


答案 1

如果两个不同的类装入器装入名为 的类,则可能会发生这种情况。AutocompleteResult

然后,这两个类被视为完全不同的类,即使它们具有相同的包和名称(甚至实现/字段/方法)。

一个常见的原因是,如果您使用某种插件系统,并且您的基类和插件类都提供相同的类。

要检查此问题,请在两个有问题的类(即 实现的接口类 的结果)上打印 Class.getClassLoader() 返回的值。DeviceAutocompleteResult.class


答案 2

当Java显然不是Java时。

我最近在Play Framework 2.6.3中遇到了这个问题,对我有帮助的是:https://www.playframework.com/documentation/2.6.x/ThreadPools#Application-class-loader

我在这里为可能有相同问题的人留下此信息。

为了更清楚地说明,有帮助的是:

在 Eager Singleton 上注入 Application,然后使用其类装入器来装入我遇到问题的类。

使其更清晰

public class Module {


 @Override
 public void configure {
   bind(TheClassLoaderLoader.class).asEagerSingleton()

public static class TheClassLoaderLoader {
  @Inject
        public TheClassLoaderLoader( Application application) {

         ClassLoader classloader = application.classloader();

                Class<?> interfaceClass = classloader.loadClass(InterfaceClass.class.getName());
                classloader.loadClass(ImplementsInterfaceClass.class.getName()).asSubclass(interfaceClass);

这里的例子 https://playframework.com/documentation/2.6.x/JavaDependencyInjection#Configurable-bindings

这种用途往往会令人沮丧EnvironmentClassNotFoundException

干杯


推荐