Montag, 21. September 2009

Generics: Generics auf Klassenebene

Zuletzt war das Thema, wozu man Generics zum Beispiel brauchen kann. In dem Beispiel gab es eine Methode, die einen generischen Typen verwendet hat, damit der Parameter mit dem tatsächlichen Typen zurückgegeben werden kann.
Methoden sind aber nur ein Ort, wo man Generics verwenden kann. Der zweite sind ganze Klassen. Dazu mache ich kein eigenes Beispiel, sondern verwende ein bestehendes: ArrayList. Beim Lernen von Collections tauchen vielleicht solche Sachen auf:

ArrayList l = new ArrayList();
l.add("a");
l.add("bb");
Iterator it = l.iterator();
while(it.hasNext()) {
System.out.println(((String) it.next()).length());
}

Die Liste enthält nur Strings, und soll auch nur Strings enthalten, aber der Compiler weiß es nicht. Das riecht schwer nach dem Einsatzgebiet für Generics!

ArrayList<String> l = new ArrayList<String>();
l.add("a");
l.add("bb");
Iterator<String> it = l.iterator();
while(it.hasNext()) {
System.out.println(it.next().length());
}

Der Klassenkopf von ArrayList sieht so aus:

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable

Der Klassenkopf enthält die Typenvariable E dreimal: einmal hinter dem Klassenname, zweimal im extends/implements. Der Wert der Typenvariable wird beim Konstruktoraufruf festgelegt: new ArrayList<String>(); Dieser generische Typ verleiht dem ganzen eine gewisse Typensicherheit:

ArrayList<String> l;
l = new ArrayList<Date>(); //funktioniert nicht
l = new ArrayList<String>(); //funktioniert

//Der rückgabetyp von ArrayList<E>.iterator() ist vom Typ Iterator<E> (also hier Iterator<String>)
Iterator<Date> it = l.iterator(); //funktioniert nicht
Iterator<String> it = l.iterator(); //funktioniert

while(it.hasNext()) {
//Ebenso liefert Iterator<E>.next() ein E (hier einen String) zurück
Date d = it.next(); //funktioniert nicht
String s = it.next(); //funktioniert
}

ArrayList<Object> l2 = l; //funktioniert auch nicht!
List<String> l2 = l; //funktioniert schon

Alle diese Fehler werden schon vom Compiler erkannt! Im letzten Punkt steckt eine Rafinesse. Warum ist ArrayList mit List, aber nicht String mit Object kompatibel? Die Antwort gibts nächstes mal!

Keine Kommentare:

Kommentar veröffentlichen