- 写在前面的话
- 引言
- 第 1 章 对象入门
- 第 2 章 一切都是对象
- 第 3 章 控制程序流程
- 第 4 章 初始化和清除
- 第 5 章 隐藏实施过程
- 第 6 章 类再生
- 第 7 章 多形性
- 第 8 章 对象的容纳
- 第 9 章 违例差错控制
- 第 10 章 Java IO 系统
- 第 11 章 运行期类型鉴定
- 第 12 章 传递和返回对象
- 第 十三 章 创建窗口和程序片
- 第 14 章 多线程
- 第 15 章 网络编程
- 第 16 章 设计范式
- 第 17 章 项目
- 附录 A 使用非 JAVA 代码
- 附录 B 对比 C++和 Java
- 附录 C Java 编程规则
- 附录 D 性能
- 附录 E 关于垃圾收集的一些话
- 附录 F 推荐读物
8.7.3 使用 Sets
Set 拥有与 Collection 完全相同的接口,所以和两种不同的 List 不同,它没有什么额外的功能。相反,Set 完全就是一个 Collection,只是具有不同的行为(这是实例和多形性最理想的应用:用于表达不同的行为)。在这里,一个 Set 只允许每个对象存在一个实例(正如大家以后会看到的那样,一个对象的“值”的构成是相当复杂的)。
Set (interface) | Each element that you add to the Set must be unique; otherwise the Set doesn’t add the duplicate element. Objects added to a Set must define equals( ) to establish object uniqueness. Set has exactly the same interface as Collection . The Set interface does not guarantee it will maintain its elements in any particular order. |
HashSet* | For Set s where fast lookup time is important. Objects must also define hashCode( ) . |
TreeSet | An ordered Set backed by a red-black tree. This way, you can extract an ordered sequence from a Set . |
Set(接口) 添加到 Set 的每个元素都必须是独一无二的;否则 Set 就不会添加重复的元素。添加到 Set 里的对象必须定义 equals(),从而建立对象的唯一性。Set 拥有与 Collection 完全相同的接口。一个 Set 不能保证自己可按任何特定的顺序维持自己的元素
HashSet* 用于除非常小的以外的所有 Set。对象也必须定义 hashCode()
ArraySet 由一个数组后推得到的 Set。面向非常小的 Set 设计,特别是那些需要频繁创建和删除的。对于小 Set,与 HashSet 相比,ArraySet 创建和反复所需付出的代价都要小得多。但随着 Set 的增大,它的性能也会大打折扣。不需要 HashCode()
TreeSet 由一个“红黑树”后推得到的顺序 Set(注释⑦)。这样一来,我们就可以从一个 Set 里提到一个顺序集合
⑦:直至本书写作的时候,TreeSet 仍然只是宣布,尚未正式实现。所以这里没有提供使用 TreeSet 的例子。
下面这个例子并没有列出用一个 Set 能够做的全部事情,因为接口与 Collection 是相同的,前例已经练习过了。相反,我们要例示的重点在于使一个 Set 独一无二的行为:
//: Set1.java // Things you can do with Sets package c08.newcollections; import java.util.*; public class Set1 { public static void testVisual(Set a) { Collection1.fill(a); Collection1.fill(a); Collection1.fill(a); Collection1.print(a); // No duplicates! // Add another set to this one: a.addAll(a); a.add("one"); a.add("one"); a.add("one"); Collection1.print(a); // Look something up: System.out.println("a.contains(\"one\"): " + a.contains("one")); } public static void main(String[] args) { testVisual(new HashSet()); testVisual(new TreeSet()); } } ///:~
重复的值被添加到 Set,但在打印的时候,我们会发现 Set 只接受每个值的一个实例。
运行这个程序时,会注意到由 HashSet 维持的顺序与 ArraySet 是不同的。这是由于它们采用了不同的方法来保存元素,以便它们以后的定位。ArraySet 保持着它们的顺序状态,而 HashSet 使用一个散列函数,这是特别为快速检索设计的)。创建自己的类型时,一定要注意 Set 需要通过一种方式来维持一种存储顺序,就象本章早些时候展示的“groundhog”(土拔鼠)例子那样。下面是一个例子:
//: Set2.java // Putting your own type in a Set package c08.newcollections; import java.util.*; class MyType implements Comparable { private int i; public MyType(int n) { i = n; } public boolean equals(Object o) { return (o instanceof MyType) && (i == ((MyType)o).i); } public int hashCode() { return i; } public String toString() { return i + " "; } public int compareTo(Object o) { int i2 = ((MyType) o).i; return (i2 < i ? -1 : (i2 == i ? 0 : 1)); } } public class Set2 { public static Set fill(Set a, int size) { for(int i = 0; i < size; i++) a.add(new MyType(i)); return a; } public static Set fill(Set a) { return fill(a, 10); } public static void test(Set a) { fill(a); fill(a); // Try to add duplicates fill(a); a.addAll(fill(new TreeSet())); System.out.println(a); } public static void main(String[] args) { test(new HashSet()); test(new TreeSet()); } } ///:~
对 equals() 及 hashCode() 的定义遵照“groundhog”例子已经给出的形式。在两种情况下都必须定义一个 equals()。但只有要把类置入一个 HashSet 的前提下,才有必要使用 hashCode()——这种情况是完全有可能的,因为通常应先选择作为一个 Set 实现。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论