9.5 泛型工具方法
泛型集合接口有一个巨大的优势——你只需要写一次方法(就可以处理很多类型)。例如,求群体中的最大值。以前的程序员通常使用循环来实现这个算法,例如求数组中的最大值:
if(a.length == 0) throw new NoSuchElementException();
T largest = a[0];
for(int i = 1; i < a.length(); i++)
if(largest.compareTo(a[i]) < 0)
largest = a[i];
不过,当你想求ArrayList中的最大值时,需要稍微修改代码:
if(v.size() == 0) throw new NoSuchElementException();
T largest = v.get(0);
for(int i = 1; i < v.size(); i++)
if(largest.compareTo(v.get(i)) < 0)
largest = v.get(i);
如果你又要求LinkedList中的最值呢?对LinkedList随机访问是低效的,不过你可以用迭代器:
if(l.isEmpty()) throw new NoSuchElementException();
Iterator<T> iter = l.iterator();
T largest = iter.next();
while(iter.hasNext()){
T next = iter.next();
if(largest.compareTo(next) < 0)
largest = next;
}
这些循环语句很繁琐易出错。你不会想要每次都写这么些东西,然后挨个测试和debug。你可能想把这些循环实现成一堆方法:
static <T extends Comparable> T max(T[] a)
static <T extends Comparable> T max(ArrayList<T> v)
static <T extends Comparable> T max(LinkedList<T> l)
这样也很不对劲好吧。想象能有效实现你算法的最高级别的接口。随机访问的方法如get和set具有比迭代器更低的层级(更具体)。在我们的任务中随机访问并不是必须的。求最值仅仅需要迭代整个数集而已。所以,我们应该不断向更高的层次,用更抽象的思想寻求解决方案,终于得到一个方案:可以求任何集合的最大值,只要这个集合实现了Collection接口:
public static <T extends Comparable> T max(Collection<T> c){
if(c.isEmpty()) throw new NoSuchElementException();
Iterator<T> iter = c.iterator();
T largest = iter.next();
while(iter.hasNext()){
T next = iter.next();
if(largest.compareTo(next) < 0)
largest = next;
}
return largest;
}
如此一来,用一个方法就能求数组,LinkedList,ArrayList的最大值了。
这是一个非常有用而且很强悍的思想,事实上,C++标准库里有一大堆方法都是用来处理泛型集合的。相比之下,Java标准库包含的类似方法要少一些,但也包括了最常用的排序,二分搜索和其他一些工具方法。
,