javaseiten.de   |   Version 0.6
 

3.5. Gebundene Typparameter

Ein Typparameter kann mit einer Schranke (Bound) versehen werden. Für das Nichtterminalsymbol TypeParamter gelten die folgenden Produktionen:

TypeParamter:
        TypeVariable TypeBound_opt
        
TypeBound:
        extends ClassOrInterfaceType AdditionalBoundList_opt
        
AdditionalBoundList:
        AdditionalBound
        AdditionalBoundList AdditionalBound
        
AddtionalBound:
        & InterfaceType

Zu dem generischen Typ Holder<E> können z.B. die parametrisierten Typen

Holder<Integer>
Holder<String>

angegeben werden. Als Typargument des generischen Typs könnte ein beliebiger Referenztyp angegeben werden. Wie die obigen Ableitungsregeln verdeutlichen kann der Typparameter mit einer Schranke versehen werden. Eine Schranke beschränkt die Referenztypen, die als Typargument verwendet werden können. Ein generischer Typ mit einem gebundenen Typparamter könnte wie folgt angegeben werden:

NumberHolder<E extends Number>

Als aktuelle Typargumente könnten in diesem Fall nur Referenztypen, die die Klasse Number erweitern und Number selbst verwendet werden. Mögliche parametrisierte Typen zu diesem generischen Typ mit gebundenem Typparameter wären:

NumberHolder<Byte>
NumberHolder<Integer>
NumberHolder<Number>

Der parametrisierte Typ NumberHolder<String> wäre jedoch nicht zulässig, da String die Klasse Number nicht erweitert. Die Verwendung dieses parametrisierten Typs in einem Java-Quellcode würde eine Fehlermeldung während der Compilierung erzeugen:

type parameter java.lang.String is not within its bound

Eine Definition des generischen Typs NumberHolder<E extends Number> könnte wie folgt aussehen:

Listing 3.9. NumberHolder.java. Verwendung eines Typparameters mit einer Schranke.

/* 
 * NumberHolder.java 
 * JDK 5
 *
 */

public class NumberHolder<E extends Number> {

  private E value;
  
  public void set(E v) {
    value = v;
  }  
  
  public E get() {
    return value;
  }
}

Eine Typschranke eines Typparamters kann sich wiederum aus mehreren Schranken zusammensetzen. Nach dem Schlüsselwort extends folgt zunächst die Angabe einer Klasse oder eines Interfaces (erste mögliche Schranke). Wie aus den Albeitungsregeln (Nichtterminalsymbol TypeBound) hervorgeht können nach der Angabe des Schlüsselzeichens "&" noch weitere Schranken für den Typparameter angegeben werden. Diese zusätzlichen Schranken bestehen jedoch aus Interfaces (Klassenangaben sind hier nicht mehr erlaubt). Ein generischer Typ, der als erste Schranke Number und als zusätzliche Schranke das Interface Comparable<E> besitzt, könnte wie folgt angegeben werden:

NumberCompareHolder<E extends Number & Comparable<E>>

Dieser generische Typ könnte z.B. mit Byte, Integer oder Double parametrisiert werden, da diese Klassen Number erweitern und gleichzeitig das Interface Comparable<E> implementieren. Ein parametrisierter Typ NumberCompareHolder<Number> ist hier jedoch nicht zulässig, da Number außerhalb der zusätzlichen Schranke liegt (das Interface wird nicht implementiert).

Abbildung 3.2. Typparameter mit unterschiedlichen Schranken. Links: Zulässige Typargumente für den gebundenen Typparameter E mit der Schranke extends Number (Auswahl). Rechts: Zulässige Typargumente für E mit der Begrenzung extends Number & Comparable<E> (wegen der zusätzlichen Schranke ist Number als aktuelles Typargument nicht mehr zulässig).

typeboundnumber.jpg

Das folgende Listing definiert den generischen Typ NumberCompareHolder<E extends Number & Comparable<E>>. Mögliche Typargumente des generischen Typs müssen zusätzlich das Interface Comparable<E> implementieren (ermöglicht ein Vergleichen von Objekten; z.B. kann der Maximalwert zweier Zahlen ermittelt werden).

Listing 3.10. NumberCompareHolder.java.

/* 
 * NumberCompareHolder.java 
 * JDK 5
 *
 */

public class NumberCompareHolder<E extends Number & Comparable<E>> {

  private E number1;
  private E number2;
  
  public void set(E n1, E n2) {
    number1 = n1;
    number2 = n2;
  }  
  
  public E getNumber1() {
    return number1;
  }
  
  public E getNumber2() {
    return number2;
  }
  
  public E max() {
    if (number1.compareTo(number2) > 0) {
      return number1;
    } else {
      return number2;
    }  
  }  
}

Das anschließende kurze Testprogramm verwendet die beiden zuvor definierten generischen Typen, die jeweils unterschiedlich gebundene Typparameter besitzen.

Listing 3.11. TestNumberHolder.java.

/* 
 * TestNumberHolder.java 
 * JDK 5
 *
 */

public class TestNumberHolder {

  public static void main(String[] args) {
    
    NumberHolder<Byte> nhb = new NumberHolder<Byte>();
    nhb.set(new Byte("1"));
    Byte b = nhb.get();
    System.out.println(b.toString());
    
    NumberHolder<Integer> nhi = new NumberHolder<Integer>();
    nhi.set(new Integer("2"));
    Integer i = nhi.get();
    System.out.println(i.toString());
    
    NumberHolder<Number> nhn = new NumberHolder<Number>();
    nhn.set(new Byte("3"));
    Number n1 = nhn.get();
    System.out.println(n1.toString());
    nhn.set(new Integer("4"));
    Number n2 = nhn.get(); 
    System.out.println(n2.toString());
        
    NumberCompareHolder<Double> nch = new NumberCompareHolder<Double>();
    nch.set(new Double(Math.random()), new Double(Math.random()));
    Double d1 = nch.getNumber1();
    Double d2 = nch.getNumber2();
    Double dm = nch.max();
    System.out.println("max(" + d1.toString() + "," + d2.toString() + ") = " + 
                       dm.toString());
  }
}

Eine mögliche Konsolenausgabe des Testprogramms wäre:

1
2
3
4
max(0.11537773347574398,0.3667514629967764) = 0.3667514629967764

 

 

 

Diese Seite nutzt Google-Dienste - siehe dazu Datenschutz.

Copyright © 2006, 2007 Harald Roeder