Java核心技术卷I:基础知识(原书第8版):12.4 类型变量的限定

铁文整理

12.4 类型变量的限定

    有时,类或方法需要对类型变量加以约束。下面是一个典型的例子。我们要计算数组中的最小元素:

 

class ArrayAlg {

    public static <T> T min(T[] a) // almost correct

    {

        if (a == null || a.length == 0)

            return null;

        T smallest = a[0];

        for (int i = 1; i < a.length; i++) {

            if (smallest.compareTo(a[i])> 0)

                smallest = a[i];

        }

        return smallest;

    }

}

    但是,这里有一个问题。请看一下min方法的代码内部,变量smallest类型为T,这意味着它可以是任何一个类的对象。怎么才能确信T所属的类有compareTo方法呢?

    解决这个问题的方案是将T限制为实现了Comparable接口(只含一个方法compareTo的标准接口)的类。可以通过对类型变量T设置限定(bound)实现这一点:

    public static <T extends Comparable> T min (T[] a) ...

    实际上Comparable接口本身就是一个泛型类型。目前,我们忽略其复杂性以及编译器产生的警告。第12.8节讨论了如何在Comparable接口中适当地使用类型参数。

    现在,泛型的min方法只能被实现了Comparable接口的类(如StringDate等)的数组调用。由于Rectangle类没有实现Comparable接口,所以调用min将会产生一个编译错误。

    C++注释:在C++中不能对模板参数的类型加以限制。如果程序员用一个不适当的类型实例化一个模板,将会在模板代码中报告一个(通常是含糊不清的)错误消息。

    读者或许会感到奇怪——在此为什么使用关键字extends而不是implements?毕竟,Comparable是一个接口。下面的符号

    <T extends BoundingType>

    表示T应该是绑定类型的子类型(subtype)。T和绑定类型可以是类,也可以是接口,选择关键字extends的原因是更接近子类的概念,并且Java的设计者也不打算在语言中再添加一个新的关键字。

    一个类型变量或通配符可以有多个限定,例如

    T extends Comparable & Serializable

    限定类型用“&”分隔,而逗号用来分隔类型变量。

    Java的继承中,可以根据需要拥有多个接口超类型,但限定中至多有一个类。如果用一个类作为限定,它必须是限定列表中的第一个。

    在例12-2的程序中,重新编写了一个泛型方法minmax。这个方法计算泛型数组的最大值和最小值,并返回Pair<T>

12-2 PairTest2.java

import java.util.*;

 

/**

 * @version 1.00 2004-05-10

 * @author Cay Horstmann

 */

public class PairTest2 {

    public static void main(String[] args) {

        GregorianCalendar[] birthdays = {

                new GregorianCalendar(1906, Calendar.DECEMBER, 9), // G. Hopper

                new GregorianCalendar(1815, Calendar.DECEMBER, 10), // A.

                                                                    // Lovelace

                new GregorianCalendar(1903, Calendar.DECEMBER, 3), // J. von

                                                                    // Neumann

                new GregorianCalendar(1910, Calendar.JUNE, 22), // K. Zuse

        };

        Pair<GregorianCalendar> mm = ArrayAlg.minmax(birthdays);

        System.out.println("min = " + mm.getFirst().getTime());

        System.out.println("max = " + mm.getSecond().getTime());

    }

}

 

class ArrayAlg {

    /**

     * Gets the minimum and maximum of an array of objects of type T.

     *

     * @param a

     *            an array of objects of type T

     * @return a pair with the min and max value, or null if a is null or empty

     */

    public static <T extends Comparable> Pair<T> minmax(T[] a) {

        if (a == null || a.length == 0)

            return null;

        T min = a[0];

        T max = a[0];

        for (int i = 1; i < a.length; i++) {

            if (min.compareTo(a[i])> 0)

                min = a[i];

            if (max.compareTo(a[i])< 0)

                max = a[i];

        }

        return new Pair<T>(min, max);

    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值