----
Was ich mir gedacht habe: aList ist vom statischem Type ArrayList<? extends Number>, dass heißt alle Elemente von aList müssen von Number erben. Integer erbt von Number also ist die Initialisierung von aList ok. Ich bekomme aber einen Compilerfehler wenn ich einen Integer in aList einfügen will. Meinem bisherigem Verständnis nach sollte das allerdings gehen, denn wie gesagt erbt Integer von Number.
...
Einer List<Object> kann also keine List<Integer> zugewiesen werden, aber es können Integer-Objekte über add() hinzugefügt werden.
Bei einer List<?> ist es umgekehrt: Ihr kann eine List<Integer> zugewiesen werden, aber es können keine Integer-Objekte über add() hinzugefügt werden.
Dies mag anfänglich widersprüchlich erscheinen. Der Grund ist folgender:
List<?> steht für eine homogene Liste von Elementen desselben Typs (oder Ableitungen derselben Superklasse), wobei der Typ unbekannt ist. Da der Typ unbekannt ist, darf nicht einfach ein Objekt eines vielleicht anderen Typs über add() hinzugefügt werden, um keine ClassCastException zu riskieren.
List<Object> steht für eine heterogene gemischte Liste von Elementen mit möglicherweise verschiedenen Typen. Da verschiedene Typen erlaubt sind, ist auch das Hinzufügen eines Integers per add() zugelassen.
no suitable method found for add(java.lang.Integer)
method java.util.ArrayList.add(int,capture#1 of ? extends java.lang.Number) is not applicable
(actual and formal argument lists differ in length)
method java.util.ArrayList.add(capture#1 of ? extends java.lang.Number) is not applicable
(actual argument java.lang.Integer cannot be converted to capture#1 of ? extends java.lang.Number by method invocation conversion)
es mag komisch klingen warum [c]List<Number>[/c] geht, aber [c]List<? extends Number>[/c] nicht, da man im ersten Fall auch ints, doubles oder floats oder seine eigene Number klasse reinstecken kann.
Generell gilt ? extends und dann etwas hinzufuegen ist meistens nicht gut
Wenn du dich weitergehend mit dem Thema beschäftigen willst, lautet das Stichwort "Varianz". In Java wird die Varianz nicht schon bei der Typdefinition angegeben (wie etwa bei Scala), sondern bei der Verwendung. Es gibt drei Fälle:
[c]List<? extends Number>[/c] ist kovariant. Ich kann (außer [c]null[/c]) nichts in die Liste hineinschreiben, da ich nicht weiß, wie der genaue Typ lautet (also ob es sich "in Wirklichkeit" um eine Integer-, Float- oder sonstige Liste handelt). Ich kann allerdings Werte vom Typ [c]Number[/c] auslesen.
[c]List<Number>[/c] ist invariant. Ich kann [c]Number[/c] oder beliebige Untertypen hineinschreiben und [c]Number[/c] wieder auslesen.
[c]List<? super Number>[/c] ist kontravariant. Bei Listen ist das eher unüblich, aber z.B. bei [c]Comparator[/c] manchmal nützlich. Es handelt sich um eine Liste von [c]Number[/c] oder dessen Obertypen (in diesem Fall käme nur [c]Object[/c] in Frage). Hineinschreiben darf man [c]Number[/c] oder alle Untertypen davon, herauslesen nur [c]Object[/c].
Das ist eigentlich simpel. Normalerweise kann in eine Liste alles mögliche reingemacht werden. Wenn du aber z.B. nur Integer haben willst gibst du eben ArrayList<Integer> an. Damit stellst du sicher das wirklich nur Integer enthalten sein können. Das geht mit jedem anderen Typen. Willst du allerdings trotzdem alle Objekte aufnehmen gib einfach ArrayList<Object> an. Sieht ordentlich aus und es gibt keine Compiler-Warnings
Das geht mit jedem anderen Typen. Willst du allerdings trotzdem alle Objekte aufnehmen gib einfach ArrayList<Object> an. Sieht ordentlich aus und es gibt keine Compiler-Warnings
Auch wenn das "funktioniert": Wenn man eine Liste von "irgendwas" braucht, hat man normalerweise beim Design etwas gründlich falsch gemacht.
Generell sollte man immer, wenn man etwas tut "um den Compiler glücklich zu machen", einmal kurz innehalten und sich fragen, ob man das wirklich will. Compilermeldungen sind dafür da, uns zu helfen, und kein lästiges Übel. Die statische Typprüfung der Sprache ist kein Käfig, dem man zu entkommen versuchen sollte, sondern ein Baugerüst, das uns Sicherheit gibt.