Подтвердить что ты не робот

Не может использовать реализованный интерфейс

Я очень смущен...

У меня есть класс, который непосредственно реализует интерфейс:

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

Кроме того, isAssignableFrom возвращает false, и я не уверен, почему:

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

из doc:

Определяет, является ли класс или интерфейсом, представленным этим объектом класса, тем же, что или суперкласс или суперповерхность , представляемый класс или интерфейс по указанному параметру класса.

Должен ли я всегда быть в состоянии применить объект к интерфейсу, который реализует его класс?

Спасибо.

4b9b3361

Ответ 1

Это может произойти, если два разных загрузчика классов загружают класс с именем AutocompleteResult.

Затем эти два класса рассматриваются как совершенно разные классы, даже если они имеют один и тот же пакет и имя (и даже реализацию/поля/методы).

Общей причиной для этого является использование какой-либо системы плагинов, и оба базовых класса и классы плагина предоставляют один и тот же класс.

Чтобы проверить эту проблему, напечатайте значение, возвращенное Class.getClassLoader() для обоих классов-нарушителей (т.е. класс интерфейса, реализованный Device, и результат AutocompleteResult.class).

Ответ 2

AKA, когда Java, по-видимому, не Java.

Недавно я столкнулся с этой проблемой с Play Framework 2.6.3, что помогло мне в этом: https://www.playframework.com/documentation/2.6.x/ThreadPools#Application-class-loader

Я оставляю эту информацию для людей, которые могут иметь одинаковую проблему.

Чтобы сделать более понятным, что помогает:

Внедрение приложения на Eager Singleton, а затем использование его загрузчика классов для загрузки классов, с которыми у меня возникли проблемы.

Чтобы сделать его понятным

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

Использует Environment, который часто вызывает разочарование ClassNotFoundException

Приветствия