Java容器Set详解

来源:互联网 发布:mac怎么玩qq飞车 编辑:程序博客网 时间:2024/06/05 10:22

欢迎阅读我的第一篇博客

本文参考Thinkin in java 4版本,由张同乐徒手编写。

Set与存储顺序

当你创建自己的类型时,要意识到Set需要一种方式来维护存储顺序,而存储顺序如何维护,则是在Set的不同实现之间会有所变化。因此,不同的Set实现不仅具有不同的行为,而且它们对于可以在特定的Set中放置的元素的类型也有不同的要求:


Set(interface) 存入Set的每个元素都必须是唯一的,因为Set不保存重复元素。加入Set的元素必须定义equals方法来已确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。

HashSet* 为快速查找而设计的Set。存入HashSet元素必须定义hashCode方法。

TreeSet 保持次序的Set,底层为树结构。使用它可以从Set中提取有序的序列。元素必须实现Comparable接口。

LinkedHashSet 具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。

上面HashSet被我打上了星号,如果没有其他限制,它就是你默认的选择,因为它对速度进行了优化。

本人对Thinking in java 罗里吧嗦的话进行了总结:

 您只要用Set,tama哒别管别的,必须给我重写equals方法和hashCode方法。

请往下瞅—上代码辣:

Set案例:

下面的示例演示为了成功使用特定的Set实现类而必须定义的方法。

import java.util.*;class SetType {  int i;  public SetType(int n) { i = n; }  public boolean equals(Object o) {    return o instanceof SetType && (i == ((SetType)o).i);  }  public String toString() { return Integer.toString(i); }}class HashType extends SetType {  public HashType(int n) { super(n); }  public int hashCode() { return i; }}class TreeType extends SetTypeimplements Comparable<TreeType> {  public TreeType(int n) { super(n); }  public int compareTo(TreeType arg) {    return (arg.i < i ? -1 : (arg.i == i ? 0 : 1));  }}public class TypesForSets {  static <T> Set<T> fill(Set<T> set, Class<T> type) {    try {      for(int i = 0; i < 10; i++)          set.add(            type.getConstructor(int.class).newInstance(i));    } catch(Exception e) {      throw new RuntimeException(e);    }    return set;  }  static <T> void test(Set<T> set, Class<T> type) {    fill(set, type);    fill(set, type); // Try to add duplicates    fill(set, type);    System.out.println(set);  }  public static void main(String[] args) {    test(new HashSet<HashType>(), HashType.class);    test(new LinkedHashSet<HashType>(), HashType.class);    test(new TreeSet<TreeType>(), TreeType.class);    // Things that don't work:    test(new HashSet<SetType>(), SetType.class);    test(new HashSet<TreeType>(), TreeType.class);    test(new LinkedHashSet<SetType>(), SetType.class);    test(new LinkedHashSet<TreeType>(), TreeType.class);    try {      test(new TreeSet<SetType>(), SetType.class);    } catch(Exception e) {      System.out.println(e.getMessage());    }    try {      test(new TreeSet<HashType>(), HashType.class);    } catch(Exception e) {      System.out.println(e.getMessage());    }  }} /* Output: (Sample)[2, 4, 9, 8, 6, 1, 3, 7, 5, 0][0, 1, 2, 3, 4, 5, 6, 7, 8, 9][9, 8, 7, 6, 5, 4, 3, 2, 1, 0][9, 9, 7, 5, 1, 2, 6, 3, 0, 7, 2, 4, 4, 7, 9, 1, 3, 6, 2, 4, 3, 0, 5, 0, 8, 8, 8, 6, 5, 1][0, 5, 5, 6, 5, 0, 3, 1, 9, 8, 4, 2, 3, 9, 7, 3, 4, 4, 0, 7, 1, 9, 6, 2, 1, 8, 2, 8, 6, 7][0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9][0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]java.lang.ClassCastException: SetType cannot be cast to java.lang.Comparablejava.lang.ClassCastException: HashType cannot be cast to java.lang.Comparable*///:~

案例详解

为了证明哪些方法对于某种特定的Set是必须的,并且同时还要避免代码重复,我们创建了三个类。基类SetType只存储一个int,并且通过toString方法产生它的值。因为所有在Set中存储的类都必须有equals方法,因此在基类中也有该方法。其等价性是基于这个int类型的值确定。

HashType集成自SetType,并且添加了hashCode方法。该方法对于放置到Set散列实现中的对象来说是必须的。

TreeType实现了Comparable接口,如果一个对象被用于任何种类的排序容器中,例如
SortedSet(TreeSet是其实现类),那么它必须实现这个接口。


存储顺序(SortedSet):

SortedSet 中的元素可以保证处于排序状态,这使得它可以通过在SortedSet接口中下列方法提供附加的功能: SortedSet 中的comparator() 方法返回一个Comparator对象,或者返回null,表示已自然方式排序。

Object first(): 返回容器中的第一个元素。
Object last(): 返回容器中的最末一个元素。
SortedSet subSet(fromElement,toElement)生成此Set的子集 范围从 fromElement(包含),toElement(不包含)

SortedSet HedSet(toElement)生成此Set的子集由小于toElement的元素组成。
SortedSet HedSet(toElement)生成此Set的子集由小于toElement的元素组成。

SortedSet案例:

//: containers/SortedSetDemo.java// What you can do with a TreeSet.import java.util.*;public class SortedSetDemo {  public static void main(String[] args) {    SortedSet<String> sortedSet = new TreeSet<String>();    Collections.addAll(sortedSet,      "one two three four five six seven eight"        .split(" "));    System.out.println(sortedSet);    String low = sortedSet.first();    String high = sortedSet.last();    System.out.println(low);    System.out.println(high);    Iterator<String> it = sortedSet.iterator();    for(int i = 0; i <= 6; i++) {      if(i == 3) low = it.next();      if(i == 6) high = it.next();      else it.next();    }    System.out.println(low);    System.out.println(high);    System.out.println(sortedSet.subSet(low, high));    System.out.println(sortedSet.headSet(high));    System.out.println(sortedSet.tailSet(low));  }} /* Output:[eight, five, four, one, seven, six, three, two]eighttwoonetwo[one, seven, six, three][eight, five, four, one, seven, six, three][one, seven, six, three, two]*///:~

*注意: SortedSet意思是“按对象的比较函数对元素排序 ”,而不是指“元素插入的次序”。
插入顺序可以用LinkedHashSet来保存。*

0 0