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:

  1. ArrayList<?> list = new ArrayList<CharSequence>();
  2. list.add(new String()); // semantisch zwar richtig, aber der Compiler kann das nicht zulassen, da sonst auch
  3. list.add(new Object()); // funktionieren wuerde
  4.  

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:

  1. ArrayList<? super CharSequence> list = new ArrayList<Object>();
  2. list.add(new String());   // funktioniert, da String von CharSequence ableitet
  3. // (und so auch nach CharSequence oder hoeher gecastet werden koennte)
  4.  

In eine ArrayList<? extends E> dürfen überhaupt keine Elemente hinzugefügt werden. Warum?
Weil sonst immer die Gefahr einer ClassCastException besteht.

Beispiel:

  1. ArrayList<? extends CharSequence> list = new ArrayList<StringBuffer>();
  2. list.add(new String()); // Compilerfehler. String leitet zwar von CharSequence ab, kann aber nicht nach StringBuffer gecastet werden.
  3.  

So, genug für heute. Im nächsten Eintrag geht es um dem lesenden Zugriff.

Comments are closed.