接口
Collection接口
一个Collection代表了一组对象,即它的元素。 Collection接口的主要用途是在需要最大通用性的地方传递对象集。例如,所有的通用对象集实现(它典型地实现了象Set或List这样的Collection的子接口)按惯例都有一个获取Collection参数的构造函数。该构造函数将一个新的Collection初始化以包含特定Collection中的所有元素,并允许调用者创建一个所期望的实现类型的Collection,它最初包含任意已知Collection中的全部元素,而不管它的子接口或实现类型。假设你有一个Collection, c, 它可能是一个List, 一个Set, 或某些其它种类的Collection. 下面一行程序则创建了一个新的ArrayList ( List接口的一个实现), 并在初始情况下包含c中的所有元素:
List l = new ArrayList(c);
Collection接口如下所示:
public interface Collection {
// Basic Operations
int size();
boolean isEmpty();
boolean contains(Object element);
boolean add(Object element); // Optional
boolean remove(Object element); // Optional
Iterator iterator();
// Bulk Operations
boolean containsAll(Collection c);
boolean addAll(Collection c); // Optional
boolean removeAll(Collection c); // Optional
boolean retainAll(Collection c); // Optional
void clear(); // Optional
// Array Operations
Object[] toArray();
Object[] toArray(Object a[]);
}假设一个Collection代表了一组对象,则接口将会完成你所期待它们所干的工作。它用方法告知你在对象集中,有多少元素(size, isEmpty);检查在对象集中是否包含给定的对象(contains);从对象集中增加和删除元素(add, remove);以及在对象集上提供迭代(iterator)。
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection APIadd方法经过了充分的一般性定义,因而它不仅对允许重复的对象集有意义,对不允许重复的对象集同样也有意义。它保证Collection在调用完成后将包含特殊的元素,并在Collection发生改变时,返回一个true 。类似地,remove方法 ㄒ搴螅山獵ollection中的特殊元素的一个单独的实例(a single instance)删除(假定Collection包含该元素), 并在Collection发生更改时返回true 。
Iterators(迭代)
用iterator方法返回的对象应该受到特别的关注。 Iterator与Enumeration非常相似,但在两个方面有所不同:
terator允许调用者在迭代过程中用精心设计的语法从底层次结构对象集中删除元素
方法名已被改进
第一点是十分重要的:
在用一个Enumeration遍历一个对象集的同时,没有任何一种从对象集中删除元素的安全方法。 这个操作的语义是不清楚的,并随着实现的不同而有所改变。
Iterator接口如下所示:
public interface Iterator {
boolean hasNext();
Object next();
void remove(); // Optional
}hasNext方法在功能上与Enumeration.hasMoreElements是相同的,而next方法在功能上与Enumeration.nextElement相同。remove方法从底层次结构Collection中删除由next返回的最后一个元素。在每次调用next时, remove方法只能被调用一次, 并在违反上述规则时,扔出异常。请注意Iterator.remove是在迭代过程中更改一个对象集的唯一安全途径;在迭代过程中,如果底层次结构对象集以任何其它方式被更改,该行为不被特别指明。
下面的小程序为你演示了如何使用一个Iterator来过滤一个Collection, 也就是,遍历该对象集, 并删除每一个不满足某些条件的元素:
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection APIstatic void filter(Collection c) {
for (Iterator i = c.iterator(); i.hasNext(); )
if (!cond(i.next()))
i.remove();
}在阅读这个简单的代码时,应注意两件事:
这些代码是多态的(polymorphic): 它可以应用于任何支持元素删除的Collection , 而不用考虑实现。 因而在对象集结构下编写一个多态算法是如此简单!
使用Enumeration而不是Iterator来编写也许是不可能的。因为当用一个Enumeration来遍历一个对象集时,没有一种安全的方法可以将一个元素从对象集中删除。
Bulk Operations(批量操作)
bulk operations可一次完成对全部Collection的某些操作。 使用上面所描述的操作,批量操作的每一步都可被模拟(或许这是缺少效率的),从这个意义上讲,批量操作是一种速记法。
containsAll: 如果目标Collection包含特定Collection (c)中的全部元素,则返回true
addAll: 将特定Collection中的所有元素添加到目标Collection中.
removeAll: 从目标Collection中删除所有同时也包含在特定Collection中的元素
retainAll: 从目标Collection中删除所有在特定Collection中不包含的元素。也就是说,在目标Collection中仅保留那些在特定Collection中也同时保留的元素。
clear: 从Collection中删除所有元素。 如果目标Collection在执行操作的过程中被更改,则addAll, removeAll, 和retainAll方法均返回true。
作为显示批量操作的能量的一个简单示例,请看下面的惯用程序,它将一个特定元素, e的全部实例从Collection, c中删除:
c.removeAll(Collections.singleton(e));
更特别地,假设你要从一个Collection中删除所有空元素:
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection APIc.removeAll(Collections.singleton(null));
这个惯用程序使用了Collections.singleton, 它是一个返回只包含特定元素且永恒不变的Set的静态方法。
Array Operations(数组操作)toArray方法可作为对象集 和期望将数组作为输入的旧的API之间的一个桥梁,它允许将一个Collection的内容转换为一个数组。没有参数的简单形式创建了一个新的Object(对象)数组。更复杂的形式允许调用者提供一个数组或选择这个输出数组的运行时类型。 例如,假设c是一个Collection。 如下程序可将c的内容倾卸到一个新分配的Object数组中,数组的长度与c中元素的数量相同。
Object[] a = c.toArray();
假设已知c仅包含字符串。下列程序则将c的内容倾卸到一个新分配String数组中,数组的长度与c中元素的数量相同。
String[] a = (String[]) c.toArray(new String[0]);
Set接口
Set是一个不包含重复元素的Collection。Set接口塑造了抽象的set数学模型。Set接口不包含除从Collection中继承的方法之外的任何其它方法。它禁止使用重复元素,同时它还增加了对equals和hashCode操作行为的限制,允许不同实现类型的Set对象可做比较。如果两个Set对象包含同样的元素,则它们是相等的。
Set接口如下所示:
public interface Set {
// Basic Operations
int size();
boolean isEmpty();
boolean contains(Object element);
boolean add(Object element); // Optional
boolean remove(Object element); // Optional
Iterator iterator();
// Bulk Operations
boolean containsAll(Collection c);
boolean addAll(Collection c); // Optional
boolean removeAll(Collection c); // Optional
boolean retainAll(Collection c); // Optional
void clear(); // Optional
// Array Operations
Object[] toArray();
Object[] toArray(Object a[]);
}JDK包含两个通用Set实现。一个是HashSet, 它将它的元素存储于哈希表中,它是一种最好的实现;另一个是TreeSet, 它将它的元素存储在一个红-黑树上,它保证了迭代顺序。
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection API这是一个简单但实用的Set惯用程序。 假设你有一个Collection, c, 并且你要创建另一个包含相同元素的Collection,但是所有重复元素已被清除。下面的程序给出了一个小技巧:
Collection noDups = new HashSet(c);
它是通过创建一个Set(按定义,Set不能包含重复元素)来达到目的的,这个Set初始包含c中的所有元素。
基本操作
size操作返回Set中元素的数量(它的集的势(cardinality))。 isEmpty方法所完成的工作正如你从字面上理解的一样。add方法将特定元素添加到Set中(如果该元素不在Set之中), 并返回一个表示该元素是否已被添加的布尔值。 类似地, remove方法从Set中删除特定元素(如果该元素存在于Set之中), 并返回表示该元素是否存在的布尔值。iterator方法返回一个在Set上的Iterator 。
以下是一个小程序, 它从它的参数列表中获得词汇并打印出任何重复词汇、不同词汇的数量以及删除了重复词汇的词汇列表:
import java.util.*;
public class FindDups {
public static void main(String args[]) {
Set s = new HashSet();
for (int i=0; i$#@60; args.length; i++)
if (!s.add(args[i]))
System.out.println("Duplicate detected: "+args[i]);
System.out.println(s.size()+" distinct words detected: "+s);
}
}现在让我们来运行这个程序:
% java FindDups i came i saw i left
Duplicate detected: i
Duplicate detected: i4 distinct words detected: [came, left, saw, i]
请注意, 该例子中的代码总是通过它的接口类型(Set )来引用对象集 , 而不是通过它的实现类型(HashSet)。这是一种被极力推荐的编程方法, 因为它给了你仅仅通过改变构造函数就可以改变实现的灵活性。如果用来存储一个对象集 的变量, 或用来传递对象集 的参数被声明为是对象集 的实现类型而不是它的接口类型的, 那么所有这样的变量和参数必须被改变以改变对象集 的实现类型。 进一步来讲, 如果程序中使用了任何在原始实现类型中存在而新的实现中没有的非标准操作, 那么将不能保证程序的正常运行。仅仅通过对象集的接口来引用对象集使你保持了诚实的作风, 因为从某种意义上讲, 它使你不能使用任何非标准操作。
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection API在上述例子中的Set的实现类型是HashSet, 它不保证Set中的元素的顺序。如果你需要你的程序按字母顺序打印词汇, 你所要做的全部工作就是将set的实现类型从HashSet改变为TreeSet。这一小小的改动会使以前例子中的命令行生成如下输出:
% java FindDups i came i saw i left
Duplicate word detected: i
Duplicate word detected: i
4 distinct words detected: [came, i, left, saw]批量操作(Bulk Operations)
批量操作特别适合于Sets: 它们执行标准集合代数(set-algebraic) 操作。假设s1和s2是Set, 以下是批量操作将做的工作:
s1.containsAll(s2): 如果s2是s1的一个subset , 返回真 (例如, 如果set s2包含s1中的所有元素, 则set s1是s2的一个subset)
s1.addAll(s2): 将s1转换到s1和s2的并集( union ) (两个sets的并集包含s1或者s2的元素)
s1.retainAll(s2): 将s1转换到s1和s2的交集( intersection ) (两个sets的交集仅包含两个sets中的共同的元素)
s1.removeAll(s2): 将s1转换到s1和s2的(不对称)差集((asymmetric) set difference) (例如, s1 - s2的差集包含在s1中但不包含在s2中的所有元素)
为了非破坏性地(不更改任何集)计算并集、交集或差集,调用者必须在调用批量操作之前,拷贝一个set , 作为其结果的惯用程序如下所示:
Set union = new HashSet(s1);
union.addAll(s2);
Set intersection = new HashSet(s1);
intersection.retainAll(s2);
Set difference = new HashSet(s1); difference.removeAll(s2);上述惯用程序的结果Set的实现类型是HashSet, 正如上面所提到的那样,它是JDK中最全面的Set实现。然而,任何通用Set实现都可能被替代。
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection API让我们重新看看上述例子中的FindDups 。 假设你要知道在参数列表中哪个词汇仅出现了一次,哪个词汇出现的次数多于一次,但是你不希望将重复词汇重复地打印。你可以通过生成两个sets来实现, 一个包含参数列表中的每一个词汇,另一个仅包含重复词汇,仅出现一次的词汇即两个sets的差集, 我们已经了解了差集的计算方法。
import java.util.*;
public class FindDups2 {
public static void main(String args[]) {
Set uniques = new HashSet();
Set dups = new HashSet();
for (int i=0; i$#@60; args.length; i++)
if (!uniques.add(args[i]))
dups.add(args[i]);
uniques.removeAll(dups); // Destructive set-difference
System.out.println("Unique words: " + uniques);
System.out.println("Duplicate words: " + dups);
}
}现在,让我们运行用我们以前使用过的相同的参数列表修改的程序:
% java FindDups2 i came i saw i left
Unique words: [came, left, saw]
Duplicate words: [i]一个较少使用的 集合代数操作是对称差集:它的元素包含在两个特定sets的某一个当中, 但不是在两个之中都包含。下列代码非破坏性地计算了对称差集:
Set symmetricDiff = new HashSet(s1);
symmetricDiff.addAll(s2);
Set tmp = new HashSet(s1);
tmp.retainAll(s2);
symmetricDiff.removeAll(tmp);数组操作
数组操作在Sets方面所做的事情与在其它Collection上所做的事情基本相同。有关描述见Collection接口lesson。
什么是Collection?
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection API核心 对象集 接口(核心对象集接口)是用来操作对象集并将它们从一个方法传递到另一个方法的接口,这些接口的基本目标是允许对它们所表示的对象集进行独立于具体细节的操作。核心 对象集 接口是对象集 架构的核心和灵魂。当你理解了如何使用这些接口时,你就了解了有关架构的大部分内容。核心 对象集 接口如下所示:

核心对象集接口形成了一个hierarchy(层次结构): Set是一种特殊的Collection, 而SortedSet是一种特殊的Set, 以此类推。请注意层次结构由两个明显不同的树构成: Map不是一个真正的Collection.
为保持可管理的核心 对象集 接口的数量,JDK不为每个对象集类型的每个变异提供单独的接口(其中可能的变异是永恒不变的、固定大小的和只能增加的),而将对每个接口的更改操作指定为可选择的(optional): 一个已知的实现可能不支持某些这样的操作。如果调用了一个不被支持的操作,对象集则扔出一个例外UnsupportedOperationException。哪个选项操作可被那些实现所支持,是由实现用文档来加以说明的。所有JDK的通用实现都支持全部选项操作。
以下四个部分将讲述如何使用四个基本核心 对象集 接口的问题。特别是讲述了使你可高效使用这些接口的惯用程序。
Collection
Collection接口是对象集层次结构的根。一个对象集代表了一组对象,这些对象被称为它的元素。某些对象集实现允许重复元素存在,而有些则不允许;有些是经过排序的,而有些则未经排序。JDK不提供这个接口的任何直接的实现:它提供诸如Set和List这样的更特殊的子接口的实现。这个接口是所有对象集所要实现的最小通用性的一般水准。Collection被用来传递对象集,并在期望得到最大通用性时操纵它们。
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection APISet
Set是一个不包含重复元素的对象集。正象你可能期望的那样,这个接口塑造了集合的抽象数学模型。它被用来表示就象是纸牌构成了洗牌手手中的牌、课程构成了学生的课程表以及过程运行于一个机器那样的集合。
List
List是一个经过排序的对象集 (有时也称作序列(sequence)). Lists可以包含重复元素。一个List用户通常可以控制List中每个元素被插入的准确位置。 用户可以通过它们的整数索引(位置)来访问元素。如果你已经使用过Vector, 你应该熟悉List的一般风格。
Map
Map是一个将键映射为一个值的对象。Maps不包含重复键:每个键最多可映射一个值。如果你使用过Hashtable, 你应该熟悉Map的一般风格。
最后两个核心 对象集 接口 (SortedSet和SortedMap) 只是Set和Map的排序版。为理解这些接口,你必须了解对象间是如何保持排序的。即使你没有使用SortedSet或SortedMap的打算,但是如果你要对Lists排序,请阅读以下章节。
对象排序
有两种对象排序的方法: Comparable接口可按实现它的类自动提供自然排序, 而Comparator接口则将把对对象排序的控制权,全部交给程序员。请注意这些不是核心 对象集 接口, 而是底层次结构结构。
既然你已经了解了有关对象排序的全部内容,请看下面的最后两个核心 对象集 接口:
SortedSet
SortedSet是一个将它的元素保持为上升顺序的Set。有几个附加操作被提供,以利用该排序。SortedSet接口一般被用在单词列表和成员列表等方面。
SortedMap
SortedMap是一个将它的映射保持为上升键顺序的Map。 它是SortedSet的Map对等物。SortedMap接口一般用在诸如词典和电话簿那样的应用程序中。