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,导致二者不一致;
浙公网安备 33010602011771号