Verwendung von Java-Generics

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);
    }
  }
}

itmapa.de - X2H V 0.18

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);
    }
  }
}
itmapa.de - X2H V 0.18

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.

Eine eigene generische Klasse

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(); 
  }
}
itmapa.de - X2H V 0.18

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");
  }
}
itmapa.de - X2H V 0.18

Mehrere generische Typen in einer Klasse

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;
  }
}
itmapa.de - X2H V 0.18

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());
  }
}
itmapa.de - X2H V 0.18

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