返回介绍

8.7.3 使用 Sets

发布于 2024-10-15 23:56:20 字数 3896 浏览 0 评论 0 收藏 0

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文