Generics Teil 2: Wildcards (und schreibender Zugriff darauf)
Komplexer werden die Generics mit der Verwendung von sogenannten Wildcards. Es gibt 3 Typen von Wildcards:
- ArrayList> - Die ArrayList kann mit jedem Typ parametisiert worden sein.
- ArrayList super E> - Die ArrayList kann mit Typ E oder einer Oberklasse von Typ E parametisiert worden sein. (E markiert dabei die untere Grenze)
- ArrayList extends E> Die ArrayList kann mit Typ E oder einer Unterklasse von Typ E parametisiert worden sein. (E markiert dabei die obere Grenze)
Jetzt wirds spannend: Der schreibende Zugriff solche Referenzen ist eingeschränkt. Beispielsweise darf ich in eine Wildcard ArrayList> nichts hinzufügen. Warum?
Weil nicht bekannt ist, mit welchen Typ diese Liste parametisiert wurde. Wenn ich in die Liste
jeden Typ einfügen könnte, dann könnte ich auch einen Typ einfügen, der nicht zum Parametertyp gecastet werden kann.
Das würde dann eine ClassCastException zur Laufzeit bedeuten. (Und das wäre wiederum unschön).
Beispiel:
In eine ArrayList super E> kann ich dagegen Typ E oder eine Unterklasse von Typ E einfügen, da garantiert ist, dass die Liste mit einer Oberklasse von Typ E (oder Typ E selbst) parametisiert wurde. Ein Cast nach E wird also immer funktionieren.
Beispiel:
- ArrayList<? super CharSequence> list = new ArrayList<Object>();
- // (und so auch nach CharSequence oder hoeher gecastet werden koennte)
In eine ArrayList extends E> dürfen überhaupt keine Elemente hinzugefügt werden. Warum?
Weil sonst immer die Gefahr einer ClassCastException besteht.
Beispiel:
- ArrayList<? extends CharSequence> list = new ArrayList<StringBuffer>();
- list.add(new String()); // Compilerfehler. String leitet zwar von CharSequence ab, kann aber nicht nach StringBuffer gecastet werden.
So, genug für heute. Im nächsten Eintrag geht es um dem lesenden Zugriff.