2011-01-28 30 views
23

Ci sono molte altre domande SO che parlano di generici che compilano OK con il compilatore di Eclipse ma non javac (ad esempio Java: Generics handled differenlty in Eclipse and javac e Generics compiles and runs in Eclipse, but doesn't compile in javac) - tuttavia questo sembra leggermente diverso.errore javac: tipi non convertibili con generici?

ho un enum classe:

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

e ho un'altra classe con un metodo che prende in oggetti arbitrari di tipi discendenti da 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; 
    ... 

Questo funziona bene in Eclipse, ma quando eseguo una costruzione pulita con ant, ricevo un paio di errori, uno sulla riga instanceof, l'altro sulla linea di trasmissione:

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]            ^

Perché questo accade e come posso aggirare questo problema in modo che venga compilato correttamente?

risposta

32

Non so perché sta accadendo, ma una soluzione è 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; 
    ... 

E 'brutto, ma funziona ...

+0

grazie. Perché è brutto? È semplice e ha un basso costo di runtime. –

+3

@Jason S: È brutto perché non riesco a capire perché è richiesto. –

+0

Questo è un bug noto, IIRC. In realtà, ci sono dozzine di bug correlati con nessuno di loro ancora risolto. – maaartinus

0

Per poter utilizzare instanceof entrambi gli operandi sono di ereditare/implementare la stessa classe/interfaccia.
E non può essere lanciato su LogEvent.Type

Non so come sia l'intero metodo, ma questo dovrebbe risolvere il problema utilizzando interfacce e non Generics.

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

Ma voglio che Enum sia il tipo base, non EventType. Ho bisogno del mio metodo per accettare valori Enum arbitrari. –

+0

Ma perché E non può essere lanciato su LogEvent.Type? E è una sottoclasse di Enum e LogEvent.Type è anche una sottoclasse di Enum. Capisco che la parte del problema è che non è solo Enum, ma Enum , non riesco proprio a capire cosa significhi esattamente. –

+0

Le altre domande su SO su questo argomento sembrano indicare che 'javac' ha un bug noto con limiti generici ricorsivi, quindi potrebbe confondersi. Per quanto riguarda ">", se non l'hai mai visto prima: http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#FAQ106 –

8

Forse è perché hai dichiarato e come qualcosa che si estende Enum <E>. Non posso dire di averlo capito completamente, ma sembra che limiti l'insieme dei tipi a qualche sottoinsieme che non può includere LogEvent.Type per qualche motivo. O forse è solo un bug nel compilatore. Sarei felice se qualcuno potrebbe spiegare più chiaramente, ma qui è quello che si può fare:

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

questo funziona ed è più elegante di una semplice fusione a un oggetto.

+1

funziona perché "E estende Enum "si riferisce ad una sottoclasse specifica di Enum (che potrebbe non essere compatibile con LogEvent.Type). mentre "E estende Enum " si riferisce a qualsiasi classe che estende Enum, di cui LogEvent.Type è una possibilità valida. – jtahlborn

+0

@jtahlborn: Il 'E estende Enum ' è standard boilerplate per qualsiasi classe che estenda correttamente Enum, che tutte le classi 'enum' fanno, e' LogEvent.Type' è una classe 'enum', quindi dovrebbe funzionare allo stesso modo, ma sembra che ci sia un bug in 'javac'. –

+0

@jtahlborn, sì, pensateci: LogEvent.Type estende Enum ? Sicuramente lo fa. Ma è esattamente ciò che intendiamo quando scriviamo "E estende Enum ", con E = LogEvent.Type. Quindi sono d'accordo che sembra un bug in javac. Infatti, "E estende Enum " e "E estende Enum " dovrebbe significare esattamente la stessa cosa perché qualsiasi tipo enum E può solo estendere Enum e nient'altro. –

4

Ho avuto un problema simile e aggiornato da jdk1.6.0_16 a jdk1.6.0_23 e è andato via senza modifiche al codice.