2011-01-28 2 views
23

Il y a plusieurs autres questions SO qui parlent de génériques compilant OK avec le compilateur Eclipse mais pas javac (c'est-à-dire Java: Generics handled differenlty in Eclipse and javac et Generics compiles and runs in Eclipse, but doesn't compile in javac) - cependant cela ressemble à un peu différent.Erreur javac: types inconvertibles avec génériques?

j'ai une enum classe:

public class LogEvent { 
    public enum Type { 
     // ... values here ... 
    } 
    ... 
} 

et j'ai une autre classe avec une méthode qui prend en objets arbitraires de types descendants de Enum:

@Override public <E extends Enum<E>> void postEvent(
    Context context, E code, Object additionalData) 
{ 
    if (code instanceof LogEvent.Type) 
    { 
     LogEvent.Type scode = (LogEvent.Type)code; 
    ... 

Cela fonctionne bien dans Eclipse, mais quand je fais un propre construit avec ant, je reçois une paire d'erreurs, un sur la ligne instanceof, l'autre sur la ligne de coulée:

443: inconvertible types 
    [javac] found : E 
    [javac] required: mypackage.LogEvent.Type 
    [javac]   if (code instanceof LogEvent.Type) 
    [javac]   ^

445: inconvertible types 
    [javac] found : E 
    [javac] required: com.dekaresearch.tools.espdf.LogEvent.Type 
    [javac]    LogEvent.Type scode = (LogEvent.Type)code; 
    [javac]            ^

Pourquoi cela se produit-il, et comment puis-je contourner ce problème pour qu'il se compile correctement?

Répondre

32

Je ne sais pas pourquoi ça se passe, mais une solution est facile:

@Override public <E extends Enum<E>> void postEvent(
    Context context, E code, Object additionalData) 
{ 
    Object tmp = code; 
    if (tmp instanceof LogEvent.Type) 
    { 
     LogEvent.Type scode = (LogEvent.Type)tmp; 
    ... 

Il est laid, mais ça fonctionne ...

+0

merci. Pourquoi est-ce moche? C'est simple et a un faible coût d'exécution. –

+3

@Jason S: C'est moche parce que je ne vois pas pourquoi c'est nécessaire. –

+0

Ceci est un bug connu, IIRC. En fait, il y a des douzaines de bugs liés dont aucun n'est encore résolu. – maaartinus

0

Pour utiliser instanceof les deux opérandes doivent hériter/implémenter la même classe/interface.
E ne peut tout simplement pas être converti en LogEvent.Type

Je ne sais pas à quoi ressemble votre méthode complète, mais cela devrait résoudre votre problème en utilisant des interfaces et non des génériques.

public interface EventType { } 
public class LogEvent { 
    public enum Type implements EventType {} 
} 

public void postEvent(Context context, EventType code, Object additionalData) { 
    if(code instanceof LogEvent.Type) { 
    } 
} 
+0

Mais je veux que Enum soit le type de base, pas EventType. J'ai besoin de ma méthode pour accepter des valeurs Enum arbitraires. –

+0

Mais pourquoi E ne peut pas être converti en LogEvent.Type? E est une sous-classe d'Enum et LogEvent.Type est une sous-classe d'Enum. Je comprends que la partie du problème est que ce n'est pas seulement Enum, mais Enum , je ne peux pas comprendre ce que cela signifie exactement. –

+0

Les autres questions SO sur ce sujet semblent indiquer que 'javac' a un bug connu avec des limites génériques récursives, alors peut-être que cela devient confus. En ce qui concerne le '' E étend Enum > ', si vous ne l'avez pas déjà vu: http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#FAQ106 –

8

Peut-être parce que vous avez déclaré E comme quelque chose qui va Enum <E>. Je ne peux pas dire que je le comprends complètement, mais il semble que cela limite l'ensemble des types à un sous-ensemble qui ne peut pas inclure LogEvent.Type pour une raison quelconque. Ou peut-être que c'est juste un bug dans le compilateur. Je serais heureux si quelqu'un pouvait l'expliquer plus clairement, mais voici ce que vous pouvez faire:

public <E extends Enum<?>> void postEvent(E code) 
{ 
    if (code instanceof LogEvent.Type) 
    { 
     LogEvent.Type scode = (LogEvent.Type)code; 
     ... 
    } 
    ... 

Cela fonctionne et il est plus élégant qu'un simple coulée à un objet.

+1

cela fonctionne parce que" E étend Enum "fait référence à une sous-classe spécifique d'Enum (qui peut ne pas être compatible avec LogEvent.Type). alors que "E extends Enum " fait référence à n'importe quelle classe qui étend Enum, dont LogEvent.Type est une possibilité valide. – jtahlborn

+0

@jtahlborn: Le 'E extends Enum ' est standard pour toute classe qui étend correctement Enum, que toutes les classes 'enum' font, et' LogEvent.Type' est une classe 'enum', donc ça devrait marcher aussi, mais il semble y avoir un bug dans 'javac'. –

+0

@jtahlborn, oui, pensez-y: est-ce que LogEvent.Type étend Enum ? C'est sûrement le cas. Mais c'est exactement ce que nous voulons dire quand nous écrivons "E extends Enum ", avec E = LogEvent.Type. Donc je suis d'accord que ça ressemble à un bug dans javac. En fait, "E étend Enum " et "E étend Enum " devrait signifier exactement la même chose parce que tout enum de type E peut seulement étendre Enum et rien d'autre. –

4

J'ai eu un problème similaire et mis à jour de jdk1.6.0_16 à jdk1.6.0_23 et il est parti sans aucun changement de code.