A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 裙下之臣 中级黑马   /  2014-10-17 10:03  /  1089 人查看  /  4 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

在前面的例子中,可以使用任意类替换类型参数。对于大多数情况这很好,但是限制能够传递给类型参数的类型有时是有用的。例如,假设希望创建一个类,而且这个类中包含一个返回数组中数字平均值的方法。希望该方法可以计算任意类型数字的平均值,包含整形、单精度浮点型以及双精度浮点型。因此,希望使用类型参数以泛型化的方式指定数字类型。见示例:
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接口。

点评

如果能自己总结,就更好了。  发表于 2014-10-18 13:05

评分

参与人数 1技术分 +1 收起 理由
杨佳名 + 1

查看全部评分

4 个回复

倒序浏览
看不懂这个,大哥
回复 使用道具 举报
感谢分享
回复 使用道具 举报
郭.威 发表于 2014-10-18 02:56
看不懂这个,大哥

慢慢学吧    慢慢的你就懂了
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马