Не может использовать реализованный интерфейс
Я очень смущен...
У меня есть класс, который непосредственно реализует интерфейс:
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:
Определяет, является ли класс или интерфейсом, представленным этим объектом класса, тем же, что или суперкласс или суперповерхность , представляемый класс или интерфейс по указанному параметру класса.
Должен ли я всегда быть в состоянии применить объект к интерфейсу, который реализует его класс?
Спасибо.
Ответы
Ответ 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
Приветствия