2014-12-31 25 views
5

I seguenti compila codice (ed esegue i test come previsto) in Eclipse:Discrepanza tra Eclipse compilatore e javac - enumerazioni, interfacce e generici

import java.util.EnumSet; 
public class EnumTest { 

    static enum Cloneables implements Cloneable { 
     One, Two, Three; 
    } 

    public <T extends Cloneable> T getOne(Class enumType) { 
     EnumSet<? extends T> set = EnumSet.allOf(enumType); 
     return set.iterator().next(); 
    } 
} 

Tuttavia, la compilazione sia con javac (JDK 7) direttamente o tramite Maven non riesce con il seguente errore:

type argument ? extends T is not within bounds of type-variable E 

Per essere onesti, la complessità delle enumerazioni + interfacce + tipo-parametri (generici) tutto in gioco in una volta mi ha buttato fuori mentre stavo scrivendo il codice, ma ho pensato che lo avevo finalmente fatto bene.

L'obiettivo è quello di scrivere il codice di chiamare in questo modo:

Cloneable something = enumTest.getOne(Cloneables.class); 

Per esempio, in Eclipse il seguente test compila e passa:

@Test 
public void testGetFirst() { 
    assertSame(Cloneables.One, getOne(Cloneables.class)); 
} 

Degli indizi su quale sia "corretta," Eclipse o javac, sono apprezzati.

anche apprezzato è qualsiasi consigli di modi alternativi per attuare l'idea: prendere una classe come param metodo che può essere utilizzato in EnumSet.allOf() e che determina anche il tipo di oggetti Enum nella EnumSet

proposito , non preoccuparti di criticare lo scopo di questo metodo; L'ho ridotto da un codice più utile/significativo. Non mi interessa discutere dei meriti di "trovare il primo elemento da un tipo di enum" - non è questo il punto di questa domanda.

+0

sembra che questo potrebbe essere un bug nel javac (JDK 1.7.0_60). La risposta accettata sotto è un work-around (e in realtà un codice più pulito). Vedi l'analisi dettagliata su https://bugs.eclipse.org/bugs/show_bug.cgi?id=456459#c7 –

risposta

4

È necessario fare in modo che T è un tipo enum, o non si incontreranno i vincoli per EnumSet:

public <T extends Enum<T> & Cloneable> T getOne(Class enumType) 

Inoltre, non è necessario il jolly nel vostro EnumSet, e si non dovrebbe usare il grezzo Class tipo:

public <T extends Enum<T> & Cloneable> T getOne(Class<T> enumType) { 
    EnumSet<T> set = EnumSet.allOf(enumType); 
    return set.iterator().next(); 
} 
+1

Non ho mai nemmeno saputo che potresti applicare l'operatore '&' quando dichiari un parametro di tipo simile. Anche dopo quasi 18 anni a scrivere codice Java, ho imparato qualcosa di nuovo oggi! –

+0

A proposito, il motivo per cui ho usato la forma grezza di 'Class' è che senza' T' estendendo 'Enum' il compilatore Eclipse non accetterebbe alcun valore per il parametro di tipo' Class'. Quindi usarlo in modo crudo era un effetto collaterale del non sapere combinare 'Cloneable' e' Enum' per 'T'. –

+0

È interessante notare che Eclipse non mi consente di dichiarare il set come 'EnumSet ' - si lamenta che * "Disallineamento associato: il tipo T non è un sostituto valido per il parametro limitato > del tipo EnumSet " *. Fortunatamente, 'EnumSet

Problemi correlati