Was bedeutet Javas Typparameter Wildcard wirklich? Was ist der wahre Unterschied zwischen Foo und Foo?

8

Für eine generische Schnittstelle:

%Vor%

Der Unterschied zwischen den beiden Feldern:

%Vor%

Ist das foo2 ein generischer Typ und foo nicht? Da ? ein Platzhalter ist (was ich denke, jeden Typ) und jeder Typ ist ein Untertyp von Object, dann würde ich Foo<?> und Foo<Object> semantisch und syntaktisch gleichwertig erwarten.

Beachten Sie jedoch Folgendes:

%Vor%

So Foo<?> und Foo<Object> sind nicht gleich syntaktisch.

Was ist hier los? Ich bin ziemlich fest daran, das zu verstehen.

    
mwsltn 07.03.2012, 01:56
quelle

5 Antworten

6

Foo<?> ist semantisch das gleiche wie Foo<? extends Object> : es ist ein Foo mit type Parameter von etwas Spezifischem, aber das einzige, was über "etwas" bekannt ist, ist, dass es eine Unterklasse von Object ist (was isn sag nicht zu viel, da alle Klassen Unterklassen von Object sind). Foo<Object> hingegen ist ein Foo mit dem Typparameter Object . Während alles mit Object zuweisungskompatibel ist, wird nicht alles mit ? kompatibel sein, wobei ? erweitert Object ist.

Hier ist ein Beispiel dafür, warum Foo<?> einen Fehler erzeugen sollte:

%Vor%

Ändern Sie jetzt Ihr Beispiel zu diesem:

%Vor%

Da i ein Integer ist, kann der Compiler foo1.foo(i) nicht kompilieren.

Beachten Sie, dass

%Vor%

wird auch nicht gemäß den Regeln für passende parametrisierte Typen da Object und String nachweisbar unterschiedliche Typen sind.

Foo (ohne Typ-Parameter überhaupt - ein roher Typ) sollte normalerweise als Programmierfehler betrachtet werden. Laut der Java-Sprachspezifikation (§4.8) ist der Der Compiler akzeptiert solchen Code, um nicht-generischen, alten Code nicht zu brechen.

Wegen Löschvorgang gibt es keinen Unterschied, wenn das Byte generiert wird Code. Das heißt, die einzigen Unterschiede zwischen diesen sind zum Zeitpunkt der Kompilierung.

    
Ted Hopp 07.03.2012 02:06
quelle
0

Nun, aufgrund der Typ-Löschung ist alles, was mit Generika zu tun hat, nur Kompilierzeit; Ich nehme an, dass Sie das syntaktisch nennen.
Ich denke, Ihre anfängliche Einschätzung ist korrekt und der wirkliche Unterschied ist, dass sie eine generische typisierte Variable ist und das normale Foo nicht.

    
MK. 07.03.2012 02:08
quelle
0

Objekt ist der Obertyp aller Typen in Java. Foo ist jedoch nicht der Supertyp von allen Foo. Der Supertyp von allen Foo ist Foo. Weitere Informationen finden Sie Ссылка .

    
tribal 07.03.2012 02:15
quelle
0

Der Platzhalter in Foo<?> zeigt an, dass Sie im aktuellen Bereich nicht wissen oder sich nicht darum kümmern, welche Art von 'Foo' Sie haben.

Foo<?> und Foo<? extends Object> sind gleich (die erste ist eine Abkürzung für die andere). Foo<Object> ist anders.

Ein konkretes Beispiel :

Sie können List zu List<?> zuweisen z.B.

%Vor%

Wenn Sie List<?> haben, können Sie size() aufrufen, weil Sie nicht wissen müssen, um welche Art von Liste es sich handelt. Und Sie können get(i) aufrufen, weil wir wissen, dass die Liste eine Art Object enthält, so dass der Compiler sie so behandelt, als ob get zurückgibt und Object .
Aber Sie können add(o) nicht aufrufen, weil Sie nicht wissen (und der Compiler weiß nicht), mit welcher Art von Liste Sie es zu tun haben.
In unserem obigen Beispiel möchten Sie list1.add(new Object()); nicht zulassen, da dies eine Liste von String s

sein soll

Der Grund für Platzhalter ist, dass Sie so etwas tun können:

%Vor%

Dieser Code kann auf jede gewünschte Liste angewendet werden, zB List<String> , List<Object> , List<Integer> usw.

Wenn die Signatur public static boolean containsNull(List<Object> list) war, dann konnten Sie List<Object> nur an sie übergeben, List<String> funktionierte nicht.

    
Tim 07.03.2012 02:18
quelle
0

Betrachten Sie diese Typen:

  • List<Object>
  • List<CharSequence>
  • List<String>

Auch wenn String ein Untertyp von CharSequence ist, der ein Untertyp von Object ist, haben diese Listentypen keine Subtyp-Supertype-Beziehungen. (Seltsamerweise ist String[] ein Untertyp von CharSequence[] , der ein Untertyp von Object[] ist, aber das ist aus historischen Gründen.)

Angenommen, wir wollen eine Methode schreiben, die eine Liste ausgibt. Wenn wir es tun

%Vor%

Dies kann nicht List<String> (ohne Hacks) drucken, da ein List<String> kein List<Object> ist. Aber mit Platzhaltern können wir

schreiben %Vor%

und übergeben Sie eine beliebige Liste.

Platzhalter können obere und untere Grenzen für zusätzliche Flexibilität haben. Angenommen, wir möchten eine Liste drucken, die nur CharSequence s enthält. Wenn wir es tun

%Vor%

Dann stoßen wir auf das gleiche Problem - wir können nur ein List<CharSequence> übergeben und unser List<String> ist kein List<CharSequence> . Aber wenn wir stattdessen

tun %Vor%

Dann können wir eine List<String> und eine List<StringBuilder> übergeben usw.

    
Daniel Lubarov 07.03.2012 02:09
quelle

Tags und Links