Java泛型-有界类型参数

时间:2020-01-09 10:35:32  来源:igfitidea点击:

当我们创建泛型类或者泛型方法时,类型参数可以用任何类类型替换,但是在某些情况下,我们可能希望限制可以在参数化类型中用作类型参数的类型。可以使用Java泛型中的有界类型参数来完成。

为什么Java泛型中需要有界类型参数

让我们尝试通过一个示例来了解它,当我们可能需要使用有界参数时。例如,我们有一个泛型类,该类具有对数字进行操作的方法,可能只想接受Number或者其子类的实例。

首先让我们看看如果不使用有界类型参数会发生什么。举例来说,我们将使用一个带有类average()的泛型类,该方法返回数字数组的平均值。我们已经定义了通用类,以便可以传递整数,双精度,浮点型的任何类型的数组。

public class BoundedType<T> {
  T[] numbers;
  BoundedType(T[] numbers){
    this.numbers = numbers;
  }

  public double average(){
    double sum = 0.0;
    for(int i = 0; i < numbers.length; i++){
      // Compile time error here
      sum += numbers[i].doubleValue();
    }
    double avg = sum/numbers.length;
    return avg;
  }
}

为了计算平均值,假设我们已经编写了一个上面给出的通用类,其中使用了doubleValue()方法为数组中的每个数字获取double类型的数字。该方法适用于任何Number类型,因为doubleValue()方法位于Number类中,并且它是所有包装类的超类。但是你会在这行得到编译时错误

sum + =数字[i] .doubleValue();

尽管我们打算始终将此通用类用于数字,但编译器无法知道这一点。对于编译器,BoundedType <T>表示T以后可以用任何类型替换,因此必须有某种机制让编译器知道类型参数将限于类型Number的参数。那就是我们在Java泛型中使用Bounded参数的地方。

如何声明有界类型参数

要声明一个有界的类型参数,请列出类型参数的名称,然后列出extends关键字,再列出一个超类(上限)

<T扩展父类>

这指定T只能由父类或者任何父类的子类替换。因此,此处的父类充当上限。

有界类型参数示例

如果我们采用与上述相同的示例,则可以将Number用作type参数的上限,以消除编译时错误。有了编译器,就知道用于type参数的类型将是Number或者其任何子类。

public class BoundedType<T extends Number> {
  T[] numbers;
  BoundedType(T[] numbers){
    this.numbers = numbers;
  }
  
  public double average(){
    double sum = 0.0;
    for(int i = 0; i < numbers.length; i++){
      // Compile time error here
      sum += numbers[i].doubleValue();
    }
    double avg = sum/numbers.length;
    return avg;
  }
  
  public static void main(String[] args) {
    Integer[] numArr = {3,4,5};
    BoundedType<Integer> obj = new BoundedType<Integer>(numArr);
    System.out.println("Average is: " + obj.average());
  }
}

Java泛型中的多个界限

类型参数也可以有多个界限。

<T扩展了A1&A2&A3>

具有多个界限的类型变量是界限中列出的所有类型的子类型。请注意,在多个边界的情况下,只有一个边界可以是一个类,而其他边界则必须是接口。如果界限之一是一类,则必须首先指定它。例如:

Class A { /* ... */ }
interface B { /* ... */ }
interface C { /* ... */ }

class D <T extends A & B & C> { /* ... */ }

Java中带有泛型方法的有界类型参数

在上面的示例中,在类级别使用了有界参数,但是我们也可以使用具有有界类型参数的泛型方法。考虑一种情况,在这种情况下,我们有一种方法可以对大于指定元素的数组中的元素数进行计数,并且已按如下所示编写了它。

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

我们在这一行收到编译器错误

如果(e>元素)

因为大于运算符(>)仅适用于基本类型,例如short,int,double,long,float,byte和char。我们不能使用>运算符比较对象。

我们将必须使用由Comparable <T>接口界定的类型参数来编译代码。

public static <T extends Comparable<T>> int countElements(T[] numbers, T element) {
  int count = 0;
  for (T e : numbers)
    if (e.compareTo(element) > 0)  // compiler error
      ++count;
  return count;
}