Set---HashSet
概述
This class implements the <tt>Set</tt> interface, backed by a hash table (actually a <tt>HashMap</tt> instance).
It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time.
This class permits the <tt>null</tt> element.
hashSet基于hashmap实现;
不保证iterator顺序;
hashSet允许null;
This class offers constant time performance for the basic operations (<tt>add</tt>, <tt>remove</tt>, <tt>contains</tt> and <tt>size</tt>), assuming the hash function disperses the elements properly among the buckets.
Iterating over this set requires time proportional to the sum of the <tt>HashSet</tt> instance's size (the number of elements) plus the "capacity" of the backing <tt>HashMap</tt> instance (the number of buckets).
Thus, it's very important not to set the initial capacity too high (or the load factor too low) if iteration performance is important.
hashSet为add、remove、contains、size操作提供O(1)时间复杂度,因为hash将元素分散到buckets;
iterator需要的时间与size成正比;
Note that this implementation is not synchronized.
If multiple threads access a hash set concurrently, and at least one of the threads modifies the set, it <i>must</i> be synchronized externally.
This is typically accomplished by synchronizing on some object that naturally encapsulates the set.
If no such object exists, the set should be "wrapped" using the {@link Collections#synchronizedSet Collections.synchronizedSet} method.
线程非同步的;
如果多个线程并发访问hashset,需要在外部进行同步;
可以使用Collections.synchronizedSet;
The iterators returned by this class's <tt>iterator</tt> method are <i>fail-fast</i>:
if the set is modified at any time after the iterator is created, in any way except through the iterator's own <tt>remove</tt> method, the Iterator throws a {@link ConcurrentModificationException}.
Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
hashset的iterator方法是fail-fast;
如果在iterator时,hashSet被修改(除了iterator的remove),将会抛出ConcurrentModificationException;
时间复杂度
add:O(1)
remove:O(1)
contains:O(1)
链路
new HashSet<>(10)
// java.util.HashSet.HashSet(int) public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); }
add(E e)
// java.util.HashSet.add public boolean add(E e) { return map.put(e, PRESENT)==null; // hashSet的元素是在hashmap的key,v永远是一个Object对象 } // java.util.HashMap.put public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }
iterator
Set<String> set = new HashSet<>(10); set.add("a");set.add("b");set.add("c");set.add("d"); Iterator<String> iterator = set.iterator(); while(iterator.hasNext()){ String next = iterator.next(); if (next.equals("a")){ set.remove(next); } }
iterator.iterator()
// set.iterator() -> java.util.HashMap.KeyIterator.iterator() // java.util.HashSet.iterator public Iterator<E> iterator() { return map.keySet().iterator(); } // java.util.HashMap.keySet public Set<K> keySet() { Set<K> ks = keySet; if (ks == null) { ks = new KeySet(); keySet = ks; } return ks; } // java.util.HashMap.KeySet final class KeySet extends AbstractSet<K> { public final Iterator<K> iterator() { return new KeyIterator(); } } // java.util.HashMap.KeyIterator final class KeyIterator extends HashIterator implements Iterator<K> { public final K next() { return nextNode().key; } } // java.util.HashMap.HashIterator abstract class HashIterator { public final boolean hasNext() { return next != null; } final HashMap.Node<K,V> nextNode() { HashMap.Node<K,V>[] t; HashMap.Node<K,V> e = next; if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (e == null) throw new NoSuchElementException(); if ((next = (current = e).next) == null && (t = table) != null) { do {} while (index < t.length && (next = t[index++]) == null); } return e; } public final void remove() { HashMap.Node<K,V> p = current; if (p == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); current = null; K key = p.key; removeNode(hash(key), key, null, false, false); expectedModCount = modCount; } }
hashSet.remove()
// java.util.HashSet.remove public boolean remove(Object o) { return map.remove(o)==PRESENT; } // java.util.HashMap.remove(java.lang.Object) public V remove(Object key) { HashMap.Node<K,V> e; return (e = removeNode(hash(key), key, null, false, true)) == null ? null : e.value; } // java.util.HashMap.removeNode final HashMap.Node<K,V> removeNode(int hash, Object key, Object value, boolean matchValue, boolean movable) { HashMap.Node<K,V>[] tab; HashMap.Node<K,V> p; int n, index; if ((tab = table) != null && (n = tab.length) > 0 && (p = tab[index = (n - 1) & hash]) != null) { HashMap.Node<K,V> node = null, e; K k; V v; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) node = p; else if ((e = p.next) != null) { if (p instanceof HashMap.TreeNode) node = ((HashMap.TreeNode<K,V>)p).getTreeNode(hash, key); else { do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { node = e; break; } p = e; } while ((e = e.next) != null); } } if (node != null && (!matchValue || (v = node.value) == value || (value != null && value.equals(v)))) { if (node instanceof HashMap.TreeNode) ((HashMap.TreeNode<K,V>)node).removeTreeNode(this, tab, movable); else if (node == p) tab[index] = node.next; else p.next = node.next; ++modCount; // 此处remove操作后,++modCount --size; afterNodeRemoval(node); return node; } } return null; }
set.remove抛ConcurrentModificationException
当使用iterator迭代时,iterator的next方法有个modCount != expectedModCount,
而hashset的remove方法执行后有个++modCount,导致二者不一致;