Java核心技术第12章(1)

第12章  泛型程序设计

    使用泛型机制编写的程序代码要比那些杂乱地使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性.泛型对于集合类尤其有用.
    至少在表面上看来,泛型很像C++中的模板.与Java一样,在C++中,模板也是最先被添加到语言中支持强类型集合的.

12.1    为什么要使用泛型程序设计

    泛型程序设计(Generic programming)意味着编写的代码可以被很多不同类型的对象所重用.例如,我们并不希望为聚集String和File对象分别设计不同的类.实际上,也不需要这样做,因为一个ArrayList类可以聚集任何类型的对象.这是一个泛型程序设计的实例.
    在Java中增加泛型类之前,泛型程序设计是用继承实现的.ArrayList类只维护一个Object引用的数组:
public class ArrayList  // before generic classes
{
    private Object[] elementData;
    ...
    public Object get(int i) { ... }
    public void add(Object o){ ... }
}
    这样实现有两个问题.当获取一个值时必须进行强制类型转换.
ArrayList files = new ArrayList();
...
String filename = (String) files.get(0);
     此外,这里没有错误检查.可以向数组列表中添加任何类的对象.
files.add(new File("..."));
    对于这个调用,编译和运行都不会出错.然而在其他地方,如果将get的结果强制类型转换为String类型,就会产生一个错误.
    泛型提供了一个更好的解决方法:类型参数(type parameters). ArrayList类有一个类型参数用来指示元素的类型:
ArrayList<String> files = new ArrayList<String>();
    这使得代码具有更好的可读性.
    注释:前面已经提到,在Java SE7及以后的版本中,构造函数可以省略泛型类型:
ArrayList<String> files = new ArrayList<>();
    省略的类型可以从变量的类型推断得出.
    编译器也可以
很好地 利用这个信息.当调用get的时候,不需要进行强制类型转换,编译器就知道返回类型为String,而不是Object:
String filename = files.get(0);
    编译器还知道ArrayList<String>中的add方法 有一个类型为String的参数,这将比使用Object类型的参数安全一些.现在, 编译器可以进行检查,避免插入错误类型的对象.例如:
files.add(new File("...")); // can only add String object to ArrayList<String>
    是无法通过编译的.出现编译错误比类在运行时出现类的强制类型转换异常要好得多. 类型参数的魅力在于:使得程序具有更好的可读性和安全性.
    那些原本涉及许多来自自通用类型(如Object或Comparable接口)的强制类型转换的代码一定会因使用类型参数而受益.

12.2    定义简单泛型类

    一个 泛型类(generic class)就是具有一个或多个类型变量的类.下面是Pair类的代码:
public class Pair<T>
{
    private T first;
    private T second;

    public Pair(){ first = null; second = null;}
    public Pair(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; }
}
    Pair类引入了一个类型变量T,用尖括号<>括起来,并放在类名的后面.泛型类可以有多个类型变量.例如,可以定义Pair类,其中第一个域和第二个域使用不同的类型:
public class Pair<T, U> { ... }
    类定义中的类型变量指定方法的返回类型以及域和局部变量的类型.例如:
private T first;    // uses the type variable
    注释:类型变量使用大写形式,且比较短,这是很常见的.在Java库中,使用变量E表示集合的元素类型,K和V分别表示表的关键字与值的类型. T(需要时还可以用临近的字母U和S)表示"任意类型".
    用具体的类型替换类型变量就可以实例化泛型类型,例如:
Pair<String>
    可以将结果想象成带有构造器的普通类:
Pair<String>()
Pair<String>(String, String)
    和方法:
String getFirst()
String getSecond()
void setFirst(String)
void setSecond(String)
    换句话说,泛型类可以看做普通类的工厂.
    程序12-1使用了Pair类.静态的minmax方法遍历了数组并同时计算出最小值和最大值.它用一个Pair对象返回了两个结果.
    注释:从表面上看,Java的泛型类类似于C++的模板类.唯一明显的不同是Java没有专用的 template 关键字.但是,在本章中将看到,这两种机制有着本质的区别.
    pair1/PairTest1.java如下所示:
package pair1;

public class PairTest1
{
    public static void main(String[] args)
    {
        String[] words = {"Mary", "had", "a", "little", "lamb"};
        Pair<String> mm = ArrayAlg.minmax(words);
        System.out.println("min = " + mm.getFirst());
        System.out.println("max = " + mm.getSecond());
    }
}

class ArrayAlg
{
    /**
     * Gets the minimum and maximum of an array of strings
     * @param a an array of strings
     * @return a pair with the min and max value, or null if a is null or empty
     */
    public static Pair<String> minmax(String[] a)
    {
        if (a == null || a.length == 0)
            return null;
        String min = a[0];
        String 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<>(min, max);
    }
}
    运行结果如下所示:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值