在前面的例子中,可以使用任意类替换类型参数。对于大多数情况这很好,但是限制能够传递给类型参数的类型有时是有用的。例如,假设希望创建一个类,而且这个类中包含一个返回数组中数字平均值的方法。希望该方法可以计算任意类型数字的平均值,包含整形、单精度浮点型以及双精度浮点型。因此,希望使用类型参数以泛型化的方式指定数字类型。见示例:
package test;
public class Stats<T> {
private T[] nums;
public Stats(T[] o) {
nums = o;
}
public double average() {
double sum = 0d;
for(int i = 0; i < nums.length; i++)
sum += nums.doubleValue(); //这里是错误的
return sum /nums.length;
}
}
在Stats类中,average()方法通过调用doubleValue(),试图获得nums数组中每个数字的double版本,因为所有数值类,比如Integer以及Double,都是Number的子类,而Number定义了doubleValue()方法,所以所有数值类型的封装器都可以使用该方法。问题是编译器不知道你正试图创建只使用数值类型的Stats对象。因此,当试图编译Stats时,会报错误,指出doubleValue()方法是未知的。为了解决这个问题,需要以某种方式告诉编译器,你打算只向T传递数值类型。此外,需要以某种方式确保实际上只传递了数值类型。
为了处理这种情况,java提供了有界类型(dounded type)。在指定类型参数时,可以创建声明超类的上界(注:在声明时,这里只有上界,也就是使用extends,没有下界,也就是不能使用super。泛型中什么时候会使用super关键字,我们后面会讲到!),所有类型参数都必须派生自超类。这是当指定类型参数时使用extends子句完成的,如下所示:
<T extends superclass>
这样就指定T只能被superclass或其子类替代。因此,superclass定义了包括superclass在内的上限。针对上例,我们可以通过将Number指定为上界,修复前面显示的Stats类,示例如下:
package test;
public class Stats<T extends Number> {
private T[] nums;
public Stats(T[] o) {
nums = o;
}
public double average() {
double sum = 0d;
for(int i = 0; i < nums.length; i++)
sum += nums.doubleValue();
return sum /nums.length;
}
}
package test;
public class BoundsDemo {
public static void main(String[] args) {
Integer inums[] = {1,2,3,4,5};
Stats<Integer> iob = new Stats<>(inums);
double v = iob.average();
System.out.println("iob average is " + v);
Double dnums[] = {1.1,2.2,3.3,4.4,5.5};
Stats<Double> dob = new Stats<>(dnums);
double w = dob.average();
System.out.println("dob average is " + w);
}
}
注意现在使用下面这行代码声明Stats的方式:
public class Stats<T extends Number> {......}
现在使用Number对类型T进行了限定,java编译器知道所有T类型的对象都可以调用doubleValue()方法,因为该方法是由Number声明的。
除了使用类作为边界之外,也可以使用接口。实际上,可以指定多个接口作为边界。此外,边界可以包含一个类和一个或多个接口。对于这种情况,必须首先指定类类型,也就是把类类型放在extends之后的第一个位置。如果边界包含接口类型,那么只有实现了那种接口的类型参数是合法的。当指定具有一个类和一个或多个接口的边界时,使用&运算符连接它们。如下:
class Gen<T extends MyClass & MyInterface> {......}
在此,通过类MyClass和接口MyInterface对T进行限制。因此,所有传递给T的类型参数都必须是MyClass的子类,并且必须实现MyInterface接口。 |