2011-11-07 9 views
29

Jestem bardzo mylić ...nie może rzutować na wdrożonego interfejsu

Mam klasy, która implementuje interfejs bezpośrednio:

public class Device implements AutocompleteResult 
{...} 

Oto dowód, że patrzę w prawo zmienne:

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

Jednak gdy próbuję rzucić instancję klasy interfejsu:

AutocompleteResult result = (AutocompleteResult) match; 

Otrzymuję wyjątek ClassCastException!

ClassCastException: Device cannot be cast to AutocompleteResult 

Również isAssignableFrom powraca fałszywa i nie jestem pewien, dlaczego:

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

z doc:

Określa, czy klasa lub interfejs przedstawiciele tej klasy obiekt jest albo taki sam, jak superklasa, albo superinterf as, klasa lub interfejs reprezentowany przez określony parametr klasy.

Czy nie powinienem zawsze móc rzucić obiekt na interfejs, który implementuje jego klasa?

Dzięki.

+0

Tak, powinieneś! (i nie powinieneś nawet potrzebować jawnej obsady). Proszę napisać samodzielny przykładowy kod demonstrujący problem. –

Odpowiedz

54

Może się to zdarzyć, jeśli dwa różne programy ładujące klasy ładują klasę o nazwie AutocompleteResult.

Te dwie klasy są następnie traktowane jako klasy z zupełnie innymi klasami, nawet jeśli mają ten sam pakiet i nazwę (a nawet implementację/pola/metody).

Powszechną tego przyczyną jest użycie pewnego rodzaju systemu wtyczek, a obie klasy bazowe i klasy wtyczek: zapewniają tę samą klasę.

Aby sprawdzić tego problemu drukować wartość zwracana przez Class.getClassLoader() na obu klas przestępczych (czyli klasa interfejsu realizowanego przez Devicei wyniku uzyskanego AutocompleteResult.class).

+1

wow, dzięki! Dosłownie rozrywałem włosy na tym. Spróbuję rozwiązać problem ładowania klas teraz ... – pstanton

+3

+1: Wypróbuj 'log.debug (match.getClass(). getInterfaces() [0] .getClassLoader()); log.debug (AutocompleteResult.class.getClassLoader()) ' –

+0

Mój problem polegał na tym, że miałem błędną importowaną klasę i pomogło mi to ustalić:' Class [] interfaces = match.getClass(). getInterfaces(); for (int i = 0; i toobsco42

0

AKA, gdy Java najwyraźniej nie obsługuje Javy.

uderzę ten problem ostatnio z play ramowego 2.6.3, co pomogło mi było to: https://www.playframework.com/documentation/2.6.x/ThreadPools#Application-class-loader

Zostawiam to info tutaj dla osób, które mogą mieć ten sam problem.

Aby uczynić go bardziej zrozumiałym, co pomaga to:

Wstrzykiwanie aplikacji na chętny Singleton, a następnie przy użyciu jego classloader załadować klas I miał problemy z.

Aby uczynić go bardziej zrozumiałym

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); 

Przykładem tutaj https://playframework.com/documentation/2.6.x/JavaDependencyInjection#Configurable-bindings

który wykorzystuje Environment często rzuca frustrujące ClassNotFoundException

Cheers

Powiązane problemy