Set集合不包含重复的元素,这是使用Set的主要原因。有三种常见的Set实现——HashSet, TreeSet和LinkedHashSet。什么时候使用它们,使用哪个是个重要的问题。
总体而言:
- 如果你需要一个访问快速的Set,你应该使用HashSet;
- 当你需要一个排序的Set,你应该使用TreeSet;
- 当你需要记录下插入时的顺序时,你应该使用LinedHashSet
HashSet
HashSet
的实现借助了 HashMap
,所以非常的简短。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object(); public HashSet() { map = new HashMap<>(); } public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); }
HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
public boolean add(E e) { return map.put(e, PRESENT)==null; }
public int size() { return map.size(); }
public boolean isEmpty() { return map.isEmpty(); }
public boolean contains(Object o) { return map.containsKey(o); }
public boolean remove(Object o) { return map.remove(o)==PRESENT; }
public void clear() { map.clear(); }
public Iterator<E> iterator() { return map.keySet().iterator(); }
|
HashSet
在存储时把元素作为HashMap
的 key
(其value
为一个定值 PRESENT)
HashSet
的不可重复性是由 HashMap
的 key
不可重复来实现的。
比较过程:当key
的 hash
值相等时,再比对 equals()
方法是否相等,若相等,则两个key
相等。
当 HashSet
添加两个’相等’的元素时,后面的元素会覆盖前面的元素。
LinkedHashSet
继承于 HashSet
,只是多了一个双向链表用来维护元素的添加顺序。
1 2 3 4 5 6 7 8 9 10 11
| HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
public LinkedHashMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); accessOrder = false; }
|
TreeSet
TreeSet的实现借助了TreeMap,基本所有的方法都是调用TreeMap实现的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable {
private transient NavigableMap<E,Object> m;
private static final Object PRESENT = new Object();
TreeSet(NavigableMap<E,Object> m) { this.m = m; }
public TreeSet() { this(new TreeMap<E,Object>()); }
public TreeSet(Comparator<? super E> comparator) { this(new TreeMap<>(comparator)); }
public TreeSet(Collection<? extends E> c) { this(); addAll(c); }
public TreeSet(SortedSet<E> s) { this(s.comparator()); addAll(s); }
public int size() { return m.size(); }
public boolean isEmpty() { return m.isEmpty(); }
public boolean contains(Object o) { return m.containsKey(o); }
public boolean add(E e) { return m.put(e, PRESENT)==null; }
public boolean remove(Object o) { return m.remove(o)==PRESENT; }
public void clear() { m.clear(); }
public boolean addAll(Collection<? extends E> c) { if (m.size()==0 && c.size() > 0 && c instanceof SortedSet && m instanceof TreeMap) { SortedSet<? extends E> set = (SortedSet<? extends E>) c; TreeMap<E,Object> map = (TreeMap<E, Object>) m; Comparator<?> cc = set.comparator(); Comparator<? super E> mc = map.comparator(); if (cc==mc || (cc != null && cc.equals(mc))) { map.addAllForTreeSet(set, PRESENT); return true; } } return super.addAll(c); } ...... }
|