Advanced Java Services | Generische Interfaces, Klassen und Methoden |
Seit Java 5 (oder 1.5) gibt es In der API eine zunehmende Zahl von Klassen und Interfaces, die generische Typen verwenden, etwa die Interfaces Comparable<T>, List<T> oder Map<K,V> oder die Klassen ArrayList<T>, HashMap<K,V> oder Class<T>. Hier werden einfache Regeln über generische Interfaces und Klassen zusammengestellt.
Wir geben uns das folgende einfache Interface vor
interface Face<T> { // T t; // Cannot make a static reference to the non-static type T void method(T t); T method(); }
Der generische Typ kann also sowohl in der Parameterliste als auch als Returntyp auftauchen. Als statische Konstante kann er dagegen nicht verwendet werden
Nun soll ein zweites Interface davon erben. Dann kann man
1) den generischen Typ einfach weglassen
interface Face1 extends Face { }
2) ihn durch einen realen Typ ersetzen
interface Face2 extends Face<String> { }
3) ihn übernehmen
interface Face3<T> extends Face<T> { }
Umgekehrt kann ein generisches Interface von einem nichtgenerischen Interface erben
interface Face<T> extends Serializable { void method(T t); }
Wenn wir nun die Kindinterfaces mit Hilfe von Klassen implementieren ergeben sich dieselben Regeln für Klassen.
Die Klasse kann
1) den generischen Typ einfach weglassen
class Klasse1 implements Face { @Override public void method(Object t) { } }
2) ihn durch einen realen Typ ersetzen
class Klasse2 implements Face<String> { @Override public void method(String t) { } }
3) ihn übernehmen
class Klasse3<T> implements Face<T> { @Override public void method(T t) { } }
Ein generischer Typ kann nicht mit new instantiiert werden (es könnte ja auch ein Interface sein).
class Xyz<T>
{
public X()
{
T t = new T(); // error: unexpected type
}
}
Ein generischer Typ zu einer Klasse ist immer nicht-statisch.
class Xyz<T>
{
static T t; // non-static type variable T cannot be referenced from a static context
}
Man kann hier den generischen Typ genauso verwenden wie einen realen Typ.
public class Member<T>
{
private T id = null;
public Member()
{
}
public Member(T id)
{
this.id = id;
}
public T getId()
{
return id;
}
public void setId(T id)
{
this.id = id;
}
public String genericTypeToString()
{
return id==null ? null : id.toString();
}
}
Die Methode genericTypeToString() erscheint etwas ungewöhnlich, ist aber legal, da eine Konkretisierung des generischen Typs sich von Object ableiten muß
Wir erweitern Comparable um eine Vergleichsmethode, die case-insensitive ist.
public interface ComparableIgnoreCase<T> extends Comparable<T> { int compareToIgnoreCase(T t); }
Die Klasse Person implementiert nun das Interface ComparableIgnoreCase für ihren eigenen Typ
public class Person implements ComparableIgnoreCase<Person> { private String vorName; private String nachName; // TODO Constructors // TODO Getters and Setters @Override public int compareTo(Person p) { int erg = nachName.compareTo(p.nachName); return erg == 0 ? vorName.compareTo(p.vorName) : erg ; } @Override public int compareToIgnoreCase(Person p) { int erg = nachName.compareToIgnoreCase(p.nachName); return erg == 0 ? vorName.compareToIgnoreCase(p.vorName) : erg ; } }
Eine Methode kann generisch sein, ohne daß es die Klasse ist. In solch einem Fall muß man die spitzen Klammern, die den Platzhalter fü den realen Typ beinhalten vor den Returntyp stellen, also etwa auch vor void und es gibt nur diesen Platz, jeder andere Ort ist falsch.
public <T> String genericTypeToString(T t) { return t.toString(); }
Noch zwei Varianten
public <T> void genericType(T t) { // do something with t } public <T> T genericType() { T t; // do something with t return t; }
Generische Methoden können static sein! Bei einer parametrisierte Klasse dagegen ist die Variable zum Typ immer nichtstatisch. Hier ein etwas interessanteres Beispiel.
public class Factory { public static <T> List<T> createList(Class<T> clazz) { return new ArrayList<T>(); } }
Hier die Verwendung
public class Main { public static void main(String[] args) { List<Integer> intList = Factory.createList(Integer.class); List<String> stringList = Factory.createList(String.class); } }