2017-04-11 9 views
1
List<Integer> ints = new ArrayList<Integer>(); 
ints.add(1); ints.add(2); 
List<? extends Number> nums = ints; 
nums.add(3.14); // compile-time error 
assertints.toString().equals("[1, 2, 3.14]"); 

Warum bekommen wir Kompilierzeit Fehler?Generics in Java-Wildcards

+0

See: http://stackoverflow.com/questions/5495383/java-generics-wildcard-question-list-extends-a?rq=1 –

+0

auch: http://stackoverflow.com/a/6439506/2928853 – jrook

Antwort

1

Dies ist wegen Typ löschen in Java-Generika. Sie können der Liste keine neuen Elemente hinzufügen, da ihr Typparameter zur Kompilierzeit nicht definiert ist. Die Liste List<? extends Number> nums bedeutet, dass Sie add Methode nicht aufrufen können.

1

List<? extends Number> bedeutet, dass wir nicht wissen, welcher Typ in der Liste ist, außer der Tatsache, dass es sich um eine Number handelt. In diesem Fall ist es ein List<Integer>. Auch wenn Sie es einem List<? extends Number> zuweisen, bleibt es grundsätzlich ein List<Integer>. Und Sie können 3,14 nicht zu einer solchen Liste hinzufügen.

Wenn dies erlaubt wurde, der folgende Code wäre gültig:

List<Integer> ints = new ArrayList<Integer>(); 
ints.add(1); ints.add(2); 
List<? extends Number> nums = ints; 
nums.add(3.14); 
Integer third = ints.get(2); 

Aber ints.get(2) keine ganze Zahl ist, so wäre es hier eine Ausnahme werfen. Besser diese Art von Problemen zur Kompilierzeit zu erfassen.

+0

Ich denke, sagen 'nums' irgendwie bleibt eine Liste von Ganzzahlen ist ein bisschen ungenau. Nicht nur Sie können keine Gleitkommazahlen hinzufügen, Sie können nicht sogar ganze Zahlen zur Liste "Anzahl" hinzufügen. 'nums.add (new Integer (1))' wird immer noch nicht kompiliert. – jrook

+0

Vereinbaren Sie mit @jrook ... an dem Punkt, an dem der Fehler auftritt, der Compiler weiß nur, dass 'nums' eine' List '. Es verfolgt nicht, was in "nums" zugewiesen worden sein könnte. Daher können Sie keinen Fehler bei der Kompilierung bekommen, weil 'nums' eine Liste von 'Integer' ist. Diese Art von Fehler kann zur Laufzeit behoben werden, obwohl sie in diesem speziellen Fall möglicherweise wegen Typlöschung nicht abgefangen werden kann. – ajb

0

Ich denke, der wichtige Teil hier ist die Instanziierung (new ArrayList<Integer>()), die eindeutig Integer an die List-Klasse übergibt. Die linke Diamant-Notation ist nicht so wichtig, solange sie kompatibel ist. Da Sie später das generische als obere Grenze von Integer, hauptsächlich Number und seine Subtypen definiert haben, ist Java in Ordnung, weil es immer noch mit den Ganzzahlen umgehen kann. Das Objekt ist im Wesentlichen immer noch ein List<Integer>.

Dies ist wie das Zuweisen einer Zeichenfolge zu einem Objekt. Es funktioniert, weil Object ein Supertyp von String ist. Hier ist die List<? extends Number> eine Art Supertype von List<Integer>. (Ich weiß, dass das Wort "Supertyp" hier falsch ist, also können Sie mich korrigieren.)

Die Instanziierung mit Generika ist eine Art Instanz der Klasse selbst und eines Objekts. Einige andere Sprachen, z.B. Python verwendet den Begriff "Metaklassen" für diese Art von Verhalten.

+0

Ich habe gesehen, "Superklasse" verwendet, wenn "Supertype" falsch ist, ist es nicht so weit falsch. – ajb