Advanced   Java   Services Generische Interfaces, Klassen und Methoden Back Next Up Home


Einleitung

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.


Generische Interfaces

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

Generische Klassen

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

Zwei wichtige Einschränkungen

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
}

Beispiel 1: Eine generische Klasse mit einem generischen Datenfeld

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ß


Beispiel 2: Erweiterung von java.lang.Comparable<T>

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

Generische Methoden

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

Statische generische Methoden

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);
   }
}
Valid XHTML 1.0 Strict top Back Next Up Home