Generics bezeichnet ein Sprachmittel für generische
Programmierung in Java, das seit Java SE 5 zur Verfügung steht (generic, dt.
allgemein). Mit Hilfe von Java-Generics können generische Typen
und generische Methoden (generische
Konstruktoren) definiert werden. Die Bezeichnung Typ
wird oft gleichbedeutend für Klasse oder Interface verwendet (Referenztypen).
Im Gegensatz zu "normalen" Typen und Methoden besitzen generische Typen und
Methoden sogenannte Typparameter. Ein Beispiel für einen
generischen Typ ist die Klasse Vector<E>
, die ein Mitglied
des "Java Collections Framework" ist.
java.util
Class Vector<E>
Methode:
boolean add(E o)
E get(int index)
Die Klasse hat den Typparameter E
, der für die Typen derjenigen
Elemente steht, welche innerhalb des Vektors gespeichert werden sollen. Mit Hilfe
der Vektorklasse und dem new
-Operator können z.B. die Instanzen
vi
und vs
erzeugt werden:
Vector<Integer> vi = new Vector<Integer>();
Vector<String> vs = new Vector<String>();
Dabei werden Vector<Integer>
und
Vector<String>
als parametrisierte Typen
und Integer
bzw. String
als (aktuelle)
Typargumente bezeichnet. Java-Generics wurden hauptsächlich
für den "Java Collections Framework" entwickelt und eingeführt, um eine gewisse
Typsicherheit zu gewährleisten. Um dies zu verdeutlichen soll die Klasse
Vector<E>
ohne Typparamter (Vector
wird dann als
Raw Type bezeichnet) wie folgt verwendet werden, wobei beim
Auslesen eine explizite Typumwandlung (Cast) notwendig ist:
Vector v = new Vector();
v.add(new Integer(3));
Integer i = (Integer)v.get(0);
System.out.println(i.toString());
Durch die erforderliche Typumwandlung besteht eine gewisse Typunsicherheit.
So könnte z.B. ein Objekt innerhalb von Vector
aufgnommen werden,
das keine Instanz der Klasse Integer
ist. Die Information, welcher
Typ an welcher Stelle im Vector
verwendet wurde, geht beim Einfügen
verloren. Bei der Typumwandlung während des Auslesens kann daher zur Laufzeit eine
ClassCastException
ausgelöst werden. Es kann daher sinnvoll sein eine
manuelle Typüberprüfung beim Auslesen durchzuführen, bevor eine Typumwandlung
erfolgt:
Vector v = new Vector();
v.add(new Integer(3));
v.add("4");
for (int j = 0; j < v.size(); j++) {
Object obj = v.get(j);
if (obj instanceof Integer) {
Integer i = (Integer)obj;
System.out.println(i.toString());
} else {
throw new IllegalArgumentException("Vector-Element " + j +
" ist kein Integer-Objekt");
}
}
Das ausgelesene Objekt obj
wird zunächst dahingehend überprüft,
ob es eine Instanz der Klasse Integer
ist. Danach kann eine sicherer
Cast durchgeführt werden. Das Beispiel gibt nach der Ausgabe von "3" auf der Konsole
eine Fehlermeldung aus, da das zweite Element ein String
-Objekt ist.
Die Verwendung von Vector<Integer>
gewährleistet hingegen eine
Typsicherheit, eine manuelle Typüberprüfung muss nicht mehr durchgeführt werden
und Typverletzungen werden bereits während der Compilierung aufgezeigt. Das
folgende kurze Listing verwendet die generische Klasse Vector<E>
,
die mit Integer
parametrisiert wurde.
Listing 3.1. GenericsExample.java
. Verwendung des parametrisierten Typen
Vector<Integer>
.
import java.util.*;
public class GenericsExample {
public static void main(String[] args) {
Vector<Integer> v = new Vector<Integer>();
v.add(new Integer(3));
Integer i = v.get(0);
System.out.println(i.toString());
}
}
Der Typparameter der Klasse Vector<E>
wird mit dem
Großbuchstaben E
bezeichnet. Dabei wird E
nicht
zufälligerweise verwendet. Per Konvention sollten die folgenden Buchstaben für
Typparamter verwendet werden:
<E> - Element
<K> - Key
<V> - Value
<N> - Number
<T> und <S> - Type
Typparamter mit der Bezeichnung K
und V
werden
z.B. bei der der Klasse HashMap<K,V>
verwendet.