web-dev-qa-db-fra.com

ne peut pas transtyper sur l'interface implémentée

je suis très confus ...

J'ai une classe qui implémente directement une interface:

public class Device implements AutocompleteResult
{...}

Voici la preuve que je regarde les bonnes variables:

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

Pourtant, lorsque je tente de convertir une instance de la classe sur l'interface:

AutocompleteResult result = (AutocompleteResult) match;

Je reçois un ClassCastException!

ClassCastException: Device cannot be cast to AutocompleteResult

De plus, isAssignableFrom renvoie false et je ne sais pas pourquoi:

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

depuis le doc :

Détermine si la classe ou interface représentée par cet objet Class est identique à, ou est une superclasse ou superinterface de la classe ou interface représentée par le paramètre Class spécifié.

Ne devrais-je pas toujours pouvoir convertir un objet en une interface implémentée par sa classe?

Merci.

35
pstanton

Cela peut arriver si deux chargeurs de classe différents chargent une classe nommée AutocompleteResult.

Ces deux classes sont alors traitées comme des classes entièrement différentes, même si elles ont le même paquet et le même nom (et même implémentation/champs/méthodes).

Une cause commune à cela est que vous utilisez un système de type plugin et que vos classes de base et les classes de plugin fournissent la même classe.

Pour vérifier ce problème, imprimez la valeur renvoyée par Class.getClassLoader() sur les deux classes incriminées (c'est-à-dire la classe de l'interface implémentée par Deviceet le résultat de AutocompleteResult.class).

61
Joachim Sauer

AKA quand Java ne semble pas Java.

Récemment, j'ai rencontré ce problème avec Play Framework 2.6.3. Ce qui m'a aidé, c'est: https://www.playframework.com/documentation/2.6.x/ThreadPools#Application-class-loader

Je laisse cette information ici pour les personnes qui pourraient avoir le même problème.

Pour clarifier, ce qui est utile est:

Injecter une application sur un Eager Singleton, puis utiliser son chargeur de classes pour charger les classes avec lesquelles je rencontrais des problèmes.

Pour le rendre plus clair

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

L'exemple ici/ https://playframework.com/documentation/2.6.x/JavaDependencyInjection#Configurable-bindings

Qui utilise Environment jette souvent un ClassNotFoundException frustrant 

À votre santé

0
João Antunes