2016-02-12 17 views
5

Dato la seguente configurazione:Java generici Enum subtyping interfaccia

public class TestType { 

    public static void main(String[] args) { 
    List<Constants> list = new ArrayList<>(); 
    accept(list); //Does not compile 
    } 

    static void accept(Iterable<MyInterface> values) { 
    for (MyInterface value : values) { 
     value.doStuff(); 
    } 
    } 
} 

interface MyInterface<T> { 
    T doStuff(); 
} 

enum Constants implements MyInterface<Integer> { 
    ONE, TWO, THREE; 

    @Override 
    public Integer doStuff() { 
    return ordinal(); 
    } 
} 

Perché non sarà il compilatore accettare l'elenco come parametro di accettare()?

List estende Iterable tramite Collection in modo che non è il problema.

D'altra parte, il compilatore mi dice che incompatible types: java.util.List<enums.Constants> cannot be converted to java.lang.Iterable<enums.MyInterface>

Ma Costanti è un MyInterface ... non è vero?

risposta

4

Il problema riguarda il funzionamento di Generics. Nello specifico, i generici non sono reificati ... il che significa che il compilatore non vedrà uno Iterable<enum.Constants> come Iterable<enum.MyInterface> anche se Costanti è una sottoclasse di MyInterface.

Tuttavia, c'è un modo per aggirarlo: Generic wildcards.

Se si modifica static void accept(Iterable<MyInterface> values) a static void accept(Iterable<? extends MyInterface> values), è deve essere lavoro.

+0

Che funziona davvero. Accetterò la risposta non appena SO, lasciami. Molte grazie! – tannerli

0

I tipi generici non ereditano in questo modo, anche se a prima vista può sembrare controintuitivo. L'utilizzo di Iterable<? extends MyInterface> ti consentirà di utilizzare qualsiasi Iterable (ad esempio, un List) di un tipo che si estende MyInterface (ad esempio Constants).

2

è necessario utilizzare Iterable<? extends MyInterface> invece di Iterable<MyInterface> perché anche se Constants è un sottotipo di MyInterface, Iterable<Constants> non è un sottotipo di Iterable<MyInterface> - e te lo mostrerò perché:

Se fosse così (cerchiamo di usare List invece di Iterable per il prossimo esempio, sarei in grado di farlo:

List<Constant> constantsList = new ArrayList<Constants>(); // list of constants 
List<MyInterface> ifaceList = constantsList; // you said this would be OK ... 
// assume MyOtherImplementation is another implmentation of MyInterface 
ifaceList.add(new MyOtherImplementation()); // OK, MyOtherImplementation implements MyInterface 
Constant myConst = constantsList.get(0); // Oops! I just got an instance of MyOtherImplementation from List<Constant> - not cool.