Die generische Programmierung erlaubt es, dass ein Typ einer Variablen selbst Variabel ist. Der Typ der Variablen wird dabei als Typparameter bezeichnet.
Generics wurden mit dem JDK 1.5 in die Programmiersprache Java eingeführt.
Weitreichende Konsequenzen der Generics sind dort in der Verwendung von Collections
zu finden. In der Vor-Generics-Zeit konnte man in den Collection Typen nur Elemente
des Typs Object
ablegen. Um die Elemente nach einer Entnahme aus der Collection
wieder in ihren ursprünglichen Typ zu erhalten, war ein Typ-Cast notwendig.
Etwige Fehler durch falsche Typumeandlungen wurden mit einer ClassCastException
zur Luafzeit quittiert.
Die Handhabung einer Collection-Klasse ohne Generics soll im folgenden Beispiel
zu einer ArrayList
gezeigt werden. Der Quelltext wurde für
die Version 1.4 vom JDK entwickelt.
import java.util.*; public class MyArrayList14 { public static void main(String[] args) { ArrayList myArrayList = new ArrayList(); myArrayList.add("123"); myArrayList.add("234"); myArrayList.add(new Integer(345)); myArrayList.add("456"); for(int i = 0; i < myArrayList.size(); ++ i) { String s = (String)myArrayList.get(i); System.out.println(s); } } }
Wie dem Quelltext leicht zu entnehmnen ist, werden die Typen
String
und Integer
dem ArrayList
hinzugefügt. Anschließend werden die Elemente dem ArrayList
als String
entnommen, was zu einer ClassCastException
zur Laufzeit führt. Zur Compile-Zeit wird kein Fehler festgestellt.
Nachfolgend der entsprechende Quelltext für die Version 1.6 von Java mit Generics.
import java.util.*;
public class MyArrayList16 {
public static void main(String[] args) {
ArrayList<String> myArrayList = new ArrayList<String>();
myArrayList.add("123");
myArrayList.add("234");
myArrayList.add(new Integer(345)); // Compiler Fehler
myArrayList.add("456");
for(int i = 0; i < myArrayList.size(); ++ i) {
String s = myArrayList.get(i);
System.out.println(s);
}
}
}
Im Beispiel MyArrayList16
wurde das ArrayList generisch mit dem Typ
String
in spitzen Klammern definiert. Ein großer Vorteil der
generischen Typangabe ist direkt beim komplilieren festzustzellen. Die Klasse
kompliliert nicht, sondern es wird wird ein Compilerfehler an der Stelle festgestellt,
wo ein Integer
dem ArrayList
hinzugefügt werden soll.
Der Hauptvorteil ist, dass der Fehler nicht erst zur Laufzeit sondern schon zur
Compile-Zeit festgestellt wird. Ein weiterer Vorteil ist, dass der Typ-Cast zu
String
entfallen kann, da nur Elemente des Typs String
in das ArrayList
aufgenommen werden.
Nachdem wir die Verwendung von Generics in Java kennengelernt haben, werden wir uns nun mit dem Thema beschäftigen Klassen zu schreiben, welche selber Gebrauch von generischen Datentypen machen.
Die möglichen generischen Typen werden nach dem Klassennamen in spitzen Klammern
angegeben. Die dort angegebenen Typen stehen stellvertretend für den Typ der später
verwendeten Referenz. In Klassem mit generischen Typen können neben Variablen generischen
Typs auch Variablen mit festgelegtem Typ (z.B. String
) verwendet werden.
Nachfolgend der Quelltext einer Klasse, welche einen variablen (generischen) Typ enthält:
public class MyGeneric<T> { private T value; public void setValue(T value) { this.value = value; } public T getValue() { return value; } public String toString() { return "MyGeneric: "+value.toString(); } }
Das nachfolgende Beispiel zeigt die Verwendung der Klasse MyGeneric
.
Nach der generischen Typfestlegung mit String
kann dem
Objekt nur noch ein String als "value" übergeben werden.
Ein Versuch dem Objekt einen anderen Typ zu übergeben würde
zu einem Fehler zur Compile-Zeit führen.
public class MyGenericTest { public static void main(String[] args) { MyGeneric<String> mg = new MyGeneric<String>(); mg.setValue("222"); } }
Möchte man mehrere generische Typen in einer Klasse verwenden, so werden dessen Stellvertreter einfach durch Komma getrennt, in der Spitzen Klammer nach der Klassendefinition aufgelistet.
Das nachfolgende Beispiel zeigt eine generische Klasse mit drei verschiedenen generischen Typen.
public class MyGeneric2<T1,T2,T3> { private T1 t1; private T2 t2; private T3 t3; public MyGeneric2(T1 t1, T2 t2, T3 t3) { this.t1 = t1; this.t2 = t2; this.t3 = t3; } public T1 getT1() { return t1; } public T2 getT2() { return t2; } public T3 getT3() { return t3; } }
Das nachfolgende Beispiel zeigt die Verwendung von MyGenerics2
public class MyGenericTest2 { public static void main(String[] args) { MyGeneric2<String,Double,Integer> my1 = new MyGeneric2<String,Double,Integer>("Hallo 1",2.3,3); MyGeneric2<String,Integer,String> my2 = new MyGeneric2<String,Integer,String>("Hallo 2",5,"Hallo 3"); System.out.println(my1.getT1()); System.out.println(my1.getT2()); System.out.println(my1.getT3()); System.out.println(my2.getT1()); System.out.println(my2.getT2()); System.out.println(my2.getT3()); } }
Der Ablauf des Programmes führt zu folgender Ausgabe af der Systemausgabe:
Hallo 1 2.3 3 Hallo 2 5 Hallo 3
Angelika Langer & Klaus Kreft
Java Generics - Parametrisierte Typen und Methoden
http://www.angelikalanger.com/Articles/JavaMagazin/Generics/GenericsPart1.html
Angelika Langer & Klaus Kreft
Java Generics - Type Erasure
http://www.angelikalanger.com/Articles/JavaMagazin/Generics/GenericsPart2.html
Torsten Horn
Generics
http://www.torsten-horn.de/techdocs/java-generics.htm
FH Wedel - University of Applied Sciences
Generics in Java 1.5
http://www.fh-wedel.de/~si/seminare/ws05/Ausarbeitung/5.generics/genjava3.htm