2014-06-19 18 views
11

Für das folgende Code-Beispiel:Java Generics: Zuordnung mit verschachtelten Platzhalter Parameter

public static class Abc<X> { } 
public static class Def<Y> { } 
public static class Ghi<Z> { } 

public void doThis() { 
    List<?> listOne; 
    List<Abc<?>> listTwo; 
    List<Abc<Def<?>>> listThree; 
    List<Abc<Def<Ghi<?>>>> listFour; 
    List<Abc<Def<Ghi<String>>>> listFive; 

    Abc<Def<Ghi<String>>> abcdef; 

    abcdef = new Abc<Def<Ghi<String>>>(); 

    listOne.add(abcdef); // line 1 
    listTwo.add(abcdef); // line 2 
    listThree.add(abcdef); // line 3 
    listFour.add(abcdef); // line 4 
    listFive.add(abcdef); // line 5 
} 

Zeilen 1, 3 und 4 nicht kompilieren:

(line 1)

The method add(capture#1-of ?) in the type List<capture#1-of ?> is not applicable for the arguments (Abc<Def<Ghi<String>>>) 

(Zeile 3)

The method add(Abc<Def<?>>) in the type List<Abc<Def<?>>> is not applicable for the arguments (Abc<Def<Ghi<String>>>) 

(Linie 4)

The method add(Abc<Def<Ghi<?>>>) in the type List<Abc<Def<Ghi<?>>>> is not applicable for the arguments (Abc<Def<Ghi<String>>>) 

Linien 2 und 5, jedoch kompilieren.

Kann jemand erklären, warum die Zeilen 1, 3 und 4 keine legalen Zuweisungen sind? Und wenn Wildcard-Parameter in diesen Zeilen nicht auf diese Weise verwendet werden können, warum ist dann die Zuweisung in Zeile 2 legal?

+0

Sehr gute Frage! Für * Zeile 1 * liegt das daran, dass Sie nichts zu einer Liste mit unbekanntem Typ hinzufügen können, außer "null". – rlegendi

Antwort

7

listOne.add(abcdef) (Zeile 1) ist ungültig, da List<?> eine Liste eines unbekannten spezifischen Typs darstellt. Zum Beispiel könnte es ein List<String> sein, also würden wir nichts hinzufügen wollen, das kein String ist. Der Compilerfehler tritt auf, weil Abc<Def<Ghi<String>>> nicht zu ? zuweisbar ist.

listTwo.add(abcdef) (Linie 2) ist gültig, weil List<Abc<?>> eine Liste von Abc s von jede Art darstellt. Das ist richtig - verschachtelt Wildcards unterscheiden sich von Platzhaltern der obersten Ebene darin, dass sie einen beliebigen Typ und nicht einen bestimmten Typ darstellen (mit anderen Worten verschachtelte Platzhalter nicht capture). Der Compiler erlaubt es, weil Abc<Def<Ghi<String>>> zu Abc<?> zuweisbar ist. Sehen Sie diesen Beitrag für die weitere Diskussion von verschachtelten Platzhalter: Multiple wildcards on a generic methods makes Java compiler (and me!) very confused

listThree.add(abcdef) (Linie 3) ist ungültig, weil List<Abc<Def<?>>> eine Liste von Abc s von Def s jeglicher Art darstellt. Generika sind nicht kovariant, daher ist Abc<Def<Ghi<String>>> nicht zu Abc<Def<?>> zuweisbar, obwohl Def<Ghi<String>> zu Def<?> zuweisbar ist. Eine List<Integer> ist aus dem gleichen Grund nicht einer List<Number> zuweisbar. Sehen Sie diesen Beitrag für eine weitere Erklärung: Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?

listFour.add(abcdef) (Linie 4) ist ungültig aus dem gleichen Grund - Abc<Def<Ghi<String>>>-Abc<Def<Ghi<?>>> nicht übertragbar ist.

listFive.add(abcdef) (Zeile 5) ist gültig, da die generischen Typen genau übereinstimmen - Abc<Def<Ghi<String>>> ist offensichtlich zu Abc<Def<Ghi<String>>> zuweisbar.

+3

Möchten Sie nachverfolgen, dass die Zuordnungsprobleme der Zeilen 3 und 4 gelöst werden können, indem Sie die Deklarationen von 'List >> listThree' in' List >> listThree' und von 'List >>>' zu 'List >>> listFour'. Danke für die kurze Erklärung und nützliche Links; es ist jetzt viel klarer. – Sumitsu