Java泛型类型参数的界限

来源:互联网 发布:淘宝店代运营可靠吗 编辑:程序博客网 时间:2024/06/07 21:11

作用

1. 限制类型参数的类型

如要定义一个类IntegerPair来存取元素类型为Integer的对偶,此类可写成如下的形式:

public class IntegerPair<T extends Integer>{   public IntegerPair() { first = null; second = null; }   public IntegerPair(T first, T second) { this.first = first;  this.second = second; }   public T getFirst() { return first; }   public T getSecond() { return second; }   public void setFirst(T newValue) { first = newValue; }   public void setSecond(T newValue) { second = newValue; }   private T first;   private T second;}

类型参数后的extends关键字表示T 的上界为Integer类型,编译器在类型擦除阶段会将T替换成Integer,生成的字节码如下所示:

Compiled from "IntegerPair.java"public class generic.bound.IntegerPair<T extends java.lang.Integer> {  public generic.bound.IntegerPair();    descriptor: ()V    Code:       0: aload_0       1: invokespecial #1                  // Method java/lang/Object."<init>":()V       4: aload_0       5: aconst_null       6: putfield      #2                  // Field first:Ljava/lang/Integer;       9: aload_0      10: aconst_null      11: putfield      #3                  // Field second:Ljava/lang/Integer;      14: return  public generic.bound.IntegerPair(T, T);    descriptor: (Ljava/lang/Integer;Ljava/lang/Integer;)V    Code:       0: aload_0       1: invokespecial #1                  // Method java/lang/Object."<init>":()V       4: aload_0       5: aload_1       6: putfield      #2                  // Field first:Ljava/lang/Integer;       9: aload_0      10: aload_2      11: putfield      #3                  // Field second:Ljava/lang/Integer;      14: return  public T getFirst();    descriptor: ()Ljava/lang/Integer;    Code:       0: aload_0       1: getfield      #2                  // Field first:Ljava/lang/Integer;       4: areturn  public T getSecond();    descriptor: ()Ljava/lang/Integer;    Code:       0: aload_0       1: getfield      #3                  // Field second:Ljava/lang/Integer;       4: areturn  public void setFirst(T);    descriptor: (Ljava/lang/Integer;)V    Code:       0: aload_0       1: aload_1       2: putfield      #2                  // Field first:Ljava/lang/Integer;       5: return  public void setSecond(T);    descriptor: (Ljava/lang/Integer;)V    Code:       0: aload_0       1: aload_1       2: putfield      #3                  // Field second:Ljava/lang/Integer;       5: return}

可见,IntegerPair支持类型为Integer及其子类型的元素,故BoundTest不会通过编译。

public class BoundTest {    public static void main(String[] args) {        IntegerPair integerPair = new IntegerPair();        integerPair.setFirst("text");    }}

由于IntegerPar的类型参数T的界限为Integer,IntegerPair setFirst的签名为(Ljava/lang/Integer;)V,故编译BoundTest时会报错,因为integerPar setFisrt传入的是String类型:

BoundTest.java:12: error: incompatible types: String cannot be converted to Integer        integerPair.setFirst("text");                             ^Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output1 error

2.实现通用算法

可以通过类型参数调用界限的方法,如NaturalNumber所示:

public class NaturalNumber<T extends Integer> {    private T n;    public NaturalNumber(T n)  { this.n = n; }    public boolean isEven() {        return n.intValue() % 2 == 0;    }    // ...}

由于类型参数T的界限为Integer,故可在T上调用Integer的方法,如initValue. 能调用界限的方法是实现通用算法的关键。考虑求某个列表中大于某个元素的算法:

public static <T> int countGreaterThan(T[] anArray, T elem) {    int count = 0;    for (T e : anArray)        if (e > elem)  // compiler error            ++count;    return count;}

由于运算符>只能在基础数据类型如short, int, long, double, float, byte和char上进行操作,无法对Object进行>操作,故编译器会报错:

GenericAlgorithm.java:19: error: bad operand types for binary operator '>'            if (e > elem)  // compiler error                  ^  first type:  T  second type: T  where T is a type-variable:    T extends Object declared in method <T>countGreaterThan(T[],T)1 error

这个问题会导致countGreaterThan方法不通用。给类型参数加上一个界限,可以很好的解决这个问题:

public interface Comparable<T> {    public int compareTo(T o);}

新的通用算法如下:

public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {    int count = 0;    for (T e : anArray)        if (e.compareTo(elem) > 0)            ++count;    return count;}

多界限

一个类型参数可有多个界限,表达方式如下:

<T extends B1 & B2 & B3>

类型变量T的类型为界限列表中任一类型的子类.zhu’ru注意:如类型参数中的某个界限为类,必须放在界限列表中的第一个位置,如MultiBounds.java所示:

public class MultiBounds {    static class A {        public void a() {        }    }    interface B {        void b();    }    interface C {        void c();    }    static class D <T extends A & B & C> {        public void d(T t) {            t.a();            t.b();            t.c();        }    }    public static void main(String[] args) {        D d = new D();        d.d(new A());    }}

D中类型参数的界限类表声明成如下形式,B为接口,类A放在界限列表的第二个位置,故编译器将会报错:

D <T extends B & A & C> 

小结

类型参数的界限可以用来限制类型变量的类型,是实现通用算法的关键;类型变量可以有多个界限。

0 0
原创粉丝点击