Beschränkte Typparameter


... [ Seminar "Java und Werkzeuge für das Web" ] ... [ Inhaltsverzeichnis ] ... [ zurück ] ... [ weiter ] ...

Übersicht: Beschränkte Typparameter


Einschränkung mit einem Typen

Es ist möglich die Typparameter, sowohl von Interfaces, Klassen als auch Methoden, einzuschränken. Dies wird an einem Beispiel verdeutlicht, dass zunächst ohne Generizität arbeitet:

01 interface Comparable {
02   public int compareTo(Object that);
03 }
04 
05 class Byte implements Comparable {
06   private byte value;
07   public Byte(byte value){ this.value = value; }
08   public byte byteValue(){ return value; }
09   public int compareTo(Byte that){
10     return this.value - that.value;
11   }
12   public int compareTo(Object that){
13     return this.compareTo((Byte) that);
14   }
15 }
16 
17 class Collections {
18   public static Comparable max(Collection xs){
19     Iterator xi = xs.iterator();
20     Comparable w = (Comparable) xi.next();
21     while(xi.hasNext()){
22       Comparable x = (Comparable) xi.next();
23       if(w.compareTo(x) < 0) w = x;
24     }
25     return w;
26   }
27 }
Bsp/Bsp12.txt

Codebeispiel 17


Auch hierzu wieder ein Testprogramm:

01 class Test {
02   public static void main(String[] args){
03     LinkedList xs = new LinkedList();
04     xs.add(new Byte(0)); xs.add(new Byte(1));
05     Byte x = (Byte) Collections.max(xs);
06 
07     LinkedList ys = new LinkedList();
08     ys.add(new Boolean(false)); ys.add(new Boolean(true));
09     Boolean y = (Boolean) Collections.max(ys); // runtime error
10   }
11 }
Bsp/Bsp13.txt

Codebeispiel 18


Der Fehler in der letzten Zeile war zu erwarten. Er tritt aber erst zur Laufzeit auf. Das Problem an diesem Beispiel ist jetzt: Wenn in der max-Methode ein Objekt aus der Collection entnommen wird, wie kann man sicherstellen, dass dieses Objekt eine compareTo-Methode implementiert? Und: wie kann man sicherstellen, dass das Argument der compareTo-Methode den gleichen Typ hat, also die Typen zu sich selbst vergleichbar sind?

Ein Beispiel mit Generizität zeigt die Lösung dieser Probleme:

01 interface Comparable<A> {
02   public int compareTo(A that);
03 }
04 
05 class Byte implements Comparable<Byte> {
06   private byte value;
07   public Byte(byte value){ this.value = value; }
08   public byte byteValue(){ return value; }
09   public int compareTo(Byte that){
10     return this.value - that.value;
11   }
12 }
13 
14 class Collections {
15   public static <A extends Comparable<A>> A max(Collection<A> xs){
16     Iterator<A> xi = xs.iterator();
17     A w = xi.next();
18     while(xi.hasNext()){
19       A x = xi.next();
20       if(w.compareTo(x) < 0) w = x;
21     }
22     return w;
23   }
24 }
Bsp/Bsp14.txt

Codebeispiel 19


Byte implementiert das Interface mit sich selbst, d.h. Bytes können mit sich selbst verglichen werden. Der Typparamter A der Methode "max" wurde durch einen anderen Typ eingeschränkt, nämlich Comparable<A>. D.h. die Methode kann nur mit einer Collection von "A"s aufgerufen werden, die auch vergleichbar zu sich selbst sind, also zu Comparable<A>. Die Einschränkung auf den Typ mit "extends Comparable<A>" erlaubt es innerhalb der Methode auf Variablen vom Typ A Methoden aus Comparable aufzurufen. Im Beispiel wird dies auf "w" mit der "compareTo" Methode genutzt. Der Aufruf ist gültig, da die Klasse auf der die Methode aufgerufen wird und der Parameter vom Typ A sind und A implementiert ja Comparable<A>.
Die zugehörige Testklasse:

01 class Test {
02   public static void main(String[] args){
03     LinkedList<Byte> xs = new LinkedList<Byte>();
04     xs.add(new Byte(0)); xs.add(new Byte(1));
05     Byte x = Collections.max(xs);
06 
07     LinkedList<Boolean> ys = new LinkedList<Boolean>();
08     ys.add(new Boolean(false)); ys.add(new Boolean(true));
09     Boolean y = Collections.max(ys); // compile error
10   }
11 }
Bsp/Bsp15.txt

Codebeispiel 20


Ganz allgemein wird also ein Typ beschränkt indem der Name gefolgt von "extends" und einer Klasse oder einem Interface geschrieben wird. Dies ist ein Unterschied zu GJ, wo zwischen Klassen und Interfaces unterschieden wurde (bei Interfaces verwendete man implements). Eine Begründung hierfür ist im Final Draft nicht angegeben.

Die beschränkende Klasse bzw. das Interface darf ebenfalls wieder parametrisiert sein. Rekusion oder gegenseitige Rekursion ist erlaubt. Dies nennt man auch F-gebundene Polymorphie [Bracha98_2] und [Canning89].

Die Einschränkung von parametrisierten Typen, die u.a. von Bertrand Meyer als sinnvolle Ergänzung zur allgemeinen Generizität beschrieben wird, ist in C++ nicht möglich ([Joyner96], S.18). Dafür erlaubt es C++ einfache Datentypen wie int als Parameter zu übergeben, was in Java nicht möglich ist. Die Begründung hierfür ist, dass in Java primitive und Referenztypen zu unterschiedlich behandelt werden und es keinen Sinn machen würde in diesem Fall die Unterscheidung aufzuheben. Daneben lassen sich primitive Typen mit homogener Übersetzung (wie in diesem Entwurf - siehe nächstes Kapitel) nur sehr schwierig implementieren. Ein automatisches "Verpacken" in die entsprechende Wrapper-Klasse ist aus Performance-Gründen nicht möglich.


[ nach oben ]

Einschränkung mit mehreren Typen

Die Final Draft Spezifikation erlaubt darüber hinaus, mehrere Interfaces anzugeben. Der erste Parameter hinter "extends" ist immer entweder eine Klasse oder ein Interface. Danach können mit einem "&" getrennt weitere Interfaces folgen. Es darf aber keine zweite Klasse angegeben werden! Dies würde zu einer Mehrfachvererbung von Klassen führen.

Es gibt einige Unstimmigkeiten zwischen der Spezifikation [Bracha01_1] und der Implementierung im derzeitigen Prototypcompiler [Prototyp01]. Laut Spezifikation gilt: Die Reihenfolge von Typen in der Beschränkung ist egal. Wenn der Typparameter A mehr als eine Beschränkung hat, ist es ein Compile-Fehler einen Bestandteil eines Objektes vom Typ A zu nutzen, wenn dieser nicht in Object definiert ist ([Bracha01_1], S. 3).

Der Compiler macht das aber ganz anders: er verwendet einfach die erste angegebene Beschränkung als Typ. Wird jetzt auf diesem Typ eine Methode aufgerufen, die in einem der anderen Beschränkungs-Typen definiert ist, fügt der Compiler Casts ein. Die Bestandteile aller angegebenen Beschränkungstypen sind also ganz normal benutzbar. Gilad Bracha hat bestätigt, dass dieser Punkt in der Spezifikation fehlerhaft ist und der Compiler korrekt arbeitet [BrachaMail].


... [ Seminar "Java und Werkzeuge für das Web" ] ... [ Inhaltsverzeichnis ] ... [ zurück ] ... [ weiter ] ... [ nach oben ] ...

valid html4 logo Code generated with AusarbeitungGenerator Version 1.1, weblink