Set也是Java集合中重要的一部分,我们常见的Set有HashSet,LinkedHashSet,TreeSet,虽然平时可能不是很常用,但是基础还要有必要学习一下的。(以下源码来自jdk1.8.0_20)
HashSet其实很简单,源代码量也比较少,学习过HashMap之后基本上看一遍就懂了,关于HashMap可以看一下之前的文章 【HashMap源码深度解析】
HashSet继承了HashSet,实现了Set接口以及Cloneable, java.io.Serializable接口。
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
从HashSet的构造参数其实就是初始化了一个HashMap。
public HashSet() { map = new HashMap<>(); } public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
public boolean add(E e) { return map.put(e, PRESENT)==null; }
public boolean contains(Object o) { return map.containsKey(o); }
public boolean remove(Object o) { return map.remove(o)==PRESENT; }
public int size() { return map.size(); }
public boolean isEmpty() { return map.isEmpty(); }
public void clear() { map.clear(); }
public Object clone() { try { HashSet<E> newSet = (HashSet<E>) super.clone(); newSet.map = (HashMap<E, Object>) map.clone(); return newSet; } catch (CloneNotSupportedException e) { throw new InternalError(e); } }
public Iterator<E> iterator() { return map.keySet().iterator(); }
LinkedHashSet更加简单,继承了HashSet,构造函数调用了上面HashSet的最后一个构造函数,用LinkedHashMap实现,其他主要方法继承自HashSet,没有单独实现。
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, java.io.Serializable {
构造函数都是调用父类HashSet的构造方法,使用LinkedHashMap的key值集合来实现。
public LinkedHashSet(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor, true); } public LinkedHashSet(int initialCapacity) { super(initialCapacity, .75f, true); } public LinkedHashSet() { super(16, .75f, true); } public LinkedHashSet(Collection<? extends E> c) { super(Math.max(2*c.size(), 11), .75f, true); addAll(c); }
从上面两种set可以看出来set其实就是用对应的map的key值集合来实现的,TreeSet对应的就是有序Map了,默认是TreeMap。关于TreeMap的构造,增加删除元素之后调整的原理可以参考 JAVA集合:TreeMap红黑树深度解析
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其实是用有序Map来实现的,默认使用TreeMap。
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 boolean add(E e) { return m.put(e, PRESENT)==null; }
public boolean addAll(Collection<? extends E> c) { // Use linear-time version if applicable 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); }
public E first() { return m.firstKey(); }
public E last() { return m.lastKey(); }
public E floor(E e) { return m.floorKey(e); }
以默认的TreeMap为例
public K floorKey(K key) { return keyOrNull(getFloorEntry(key)); } final Entry<K,V> getFloorEntry(K key) { Entry<K,V> p = root; while (p != null) { //根节点不为null,进入循环,否则直接返回null int cmp = compare(key, p.key); if (cmp > 0) { //如果key大于当前节点 if (p.right != null) //如果right不为null,说明有更大的节点,继续循环right节点 p = p.right; else //否则说明当前节点最大,并且小于key,直接返回 return p; } else if (cmp < 0) { //如果key小于当前节点,则查找左子树 if (p.left != null) { //如果left不为null,继续循环left p = p.left; } else { //否则查找比当前节点更小的节点(向上查找) Entry<K,V> parent = p.parent; Entry<K,V> ch = p; while (parent != null && ch == parent.left) { //如果当前节点是左孩子,说明父节点较大,继续向上查找 ch = parent; parent = parent.parent; } //直到节点是右孩子,此时的父节点比当前节点小,继续循环父节点 return parent; } } else //如果相等,直接返回 return p; } return null; }
public E ceiling(E e) { return m.ceilingKey(e); }
以TreeMap为例,此方法和上面的getFloorEntry方法正好相反
public K ceilingKey(K key) { return keyOrNull(getCeilingEntry(key)); } final Entry<K,V> getCeilingEntry(K key) { Entry<K,V> p = root; while (p != null) { int cmp = compare(key, p.key); if (cmp < 0) { if (p.left != null) p = p.left; else return p; } else if (cmp > 0) { if (p.right != null) { p = p.right; } else { Entry<K,V> parent = p.parent; Entry<K,V> ch = p; while (parent != null && ch == parent.right) { ch = parent; parent = parent.parent; } return parent; } } else return p; } return null; }
public E higher(E e) { return m.higherKey(e); }
public E lower(E e) { return m.lowerKey(e); }
public E pollFirst() { Map.Entry<E,?> e = m.pollFirstEntry(); return (e == null) ? null : e.getKey(); }
以TreeMap为例,获取第一个元素,如果不为null,则删除,如果为null,则新建一个entry返回
public Map.Entry<K,V> pollFirstEntry() { Entry<K,V> p = getFirstEntry(); Map.Entry<K,V> result = exportEntry(p); if (p != null) deleteEntry(p); return result; } static <K,V> Map.Entry<K,V> exportEntry(TreeMap.Entry<K,V> e) { return (e == null) ? null : new AbstractMap.SimpleImmutableEntry<>(e); }
public E pollLast() { Map.Entry<E,?> e = m.pollLastEntry(); return (e == null) ? null : e.getKey(); }
public boolean contains(Object o) { return m.containsKey(o); }
public boolean remove(Object o) { return m.remove(o)==PRESENT; }
public void clear() { m.clear(); }
public boolean isEmpty() { return m.isEmpty(); }
public Iterator<E> iterator() { return m.navigableKeySet().iterator(); }
public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { return new TreeSet<>(m.subMap(fromElement, fromInclusive, toElement, toInclusive)); }
Set其实就是Map的key集合,用Map来实现Set,所以掌握了Map基本上就学会了Set。