Generische Klassen (Generics)

Duke mit Templates

Generische (engl. generic)  Klassen, Schnittstellen und Methoden wurden in Java in der Version 5.0 eingeführt.

Generisch bedeutet in diesem Zusammenhang, dass die entsprechenden Klassen, Methoden und Schnittstellen parametrisierbare Typen verwenden. Ein Übergabetyp ist also nicht im Quellcode festgelegt, er kann bei der Verwendung zum Übersetzungszeitpunkt verschiedene Ausprägungen annehmen.

Das Konzept der generischen Klassen erhöht die Typsicherheit im Zusammenhang mit Polymorphismus und Vererbung. Eine Erhöhung der Typsicherheit bedeutet, dass der Entwickler weniger explizite Casts verwenden muss um Typkonversionen und Anpassungen zu erzwingen.

Definition
Generische Klasse
Verwendet eine Klasse formale Typ-Parameter so nennt man sie generische Klasse. Der formale Typ-Parameter ist ein symbolischer Typ der wie ein normaler Bezeichner in Java aufgebaut ist. Er wird nach dem Klassennamen in spitzen Klammern angegeben.

Am einfachsten lässt sich das Konzept an einem Beispiel einer Klasse Koordinate mit einem parametrisierbaren Typen <T> veranschaulichen:

public class Koordinate<T> {
   private T x;
   private T y;

   Koordinate(T p1, T p2) {
      x = p1;
      y = p2;
   }
   ...
}

In dieser Implementierung der Klasse wird der eigentliche Typ der Komponenten (x und y) der Klasse Koordinate nicht konkret festgelegt. Ein Konsument dieser Klasse kann sich entscheiden diese Implementierung für Integer, Float oder Double zu verwenden. Die allgemeine Syntaxregel für die Deklaration einer generischen Klasse lautet:

Syntaxregel
Deklaration einer generischen Klasse
class Klassenname < Typvariablenliste > {//Body}

 

Will man die Implementierung der generischen Klasse Koordinate für große Fließkommazahlen verwenden, so benutzt man die folgende Syntax:

Koordinate<Double> eineKoordinate = new Koordinate<Double>(2.2d, 3.3d);

Der Typ ist parametrisierbar und wird Teil des Variablennamens bzw. des Klassennamens. Die allgemeine Syntax zum Erzeugen eines Objekts einer generischen Klasse lautet:

Syntaxregel
Instanziieren einer generischen Klasse
new Klassenname < Typliste > ( Parameterliste);

 

Will man kleinere Fließkommazahlen benutzen, so kann man die Klasse Koordinate auch mit dem Typ Float parametrisieren:

Koordinate<Float> nochEineKoordinate = new Koordinate<Float>(4.4f, 5.5f);

 Beispiel einer einfachen generischen Klasse

Die Klasse Koordinate hat ein Hauptprogramm main() welches zwei Instanzen mit unterschiedlichen Ausprägungen erzeugt und bei der Ausgabe der Werte die Methode toString() implizit aufruft:

package s2.generics;

/**
*
* @author s@scalingbits.com
* @param <T> Generischer Typ der Klasse Koordinate
*/
public class Koordinate<T> {
   private T x;
   private T y;

   public T getX() {return x;}
   public void setX(T x) {this.x = x;}
   public T getx() {return x;}
   public void setY(T y) { this.y = y;}
   public T getY() {return y;}

   public Koordinate(T xp, T yp ) {
      x = xp;
      y = yp;
   }

   @Override
   public String toString() {return "x: " + x + "; y: " + y;}

   public static void main (String[] args) {
      Koordinate<Double> k1 = new Koordinate<Double>(2.2d, 3.3d);
      System.out.println(k1);

      Koordinate<Integer> k2 = new Koordinate<Integer>(2, 3);
      System.out.println(k2);

      Koordinate<Number> k3 = new Koordinate<Number>(4.4f, 5.5f);
      System.out.println(k3);
   } // Ende main()
} // Ende Klasse Koordinate

Bei der Ausführung ergibt sich die folgende Konsolenausgabe:

x: 2.2; y: 3.3
x: 2; y: 3
x: 4.4; y: 5.5