因为HashSet底层是使用HashMap实现的,或者说它只使用key,是一个删减版的HashMap,所以只简单讲一下
它的实现。
先看一下的主要数据成员(可以很清晰的看到它使用一个final修饰的Object对象作为value,这个值是不会变的,所以不能往里面存其他的value):
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
再看一下它的构造方法(很清晰的可以看出和HashMap构造方法没什么差别,因为它就是用了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);
}
再看一下的它添加方法add和删除方法remove,因为value不变,所以没有get方法
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
public void clear() {
map.clear();
}
是不是觉得很简单,HashSet实现就介绍到这里,接下来将一下HashMap中的迭代器实现。
首先说下迭代器的功能:多用在集合上,实现遍历集合中的每个元素。
迭代器的定义(它是一个接口,里面3个主要的方法,最常用的是hashNext()和next()):
public interface Iterator<E> {
//判断是否有下个元素
boolean hasNext();
//获取下一个元素
E next();
//删除当前元素
default void remove() {
throw new UnsupportedOperationException("remove");
}
//这个先不管
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
迭代器设计用了一个迭代器模式,这里就不做详细介绍,说个流程,有兴趣的自己找资料。(先在接口定义方法,这些方法用来遍历集合中所有元素,这个接口叫迭代器Iterator,然后在集合中定义一个获取迭代器的方法iterator(),具体的集合子类就需要去实现这个方法,返回一个迭代器对象,目前我看到都是使用内部类实现迭代器接口,然后子类通过获取迭代器方法持有这个类的对象,现在要将的就是HashMap这个具体的集合子类)
先给出最终实现迭代器的类型源码(可能和之前说的有点不一样,这个一个抽象类,不能实例化,这个因为HashMap需要实现三个不同的迭代器,但迭代过程一样,所以用3个类分别去继承就好了)。
//它的方法都不是抽象的,但不需要实例化这个类
abstract class HashIterator {
Node<K,V> next; // next entry to return
Node<K,V> current; // current entry
int expectedModCount; // for fast-fail
int index; // current slot
//将next定位到table有元素的位置,从下标0开始查找
HashIterator() {
expectedModCount = modCount;
Node<K,V>[] t = table;
current = next = null;
index = 0;
if (t != null && size > 0) { // advance to first entry
do {} while (index < t.length && (next = t[index++]) == null);
}
}
//当next不为空,返回true
public final boolean hasNext() {
return next != null;
}
final Node<K,V> nextNode() {
Node<K,V>[] t;
//将next指向元素赋给e
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
//将e赋给current,并将next指向e.next,判断是否为空(是否有链)且table不为空表,
然后将next指向table下一个有元素的位置(好像源码很常见在判断语句中写赋值语句,即使条
件不成立也做了一些事情)
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
public final void remove() {
//将当前位置赋给p
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
//将current置为空,所以它也不能连续删除
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
然后再贴出继承HashIterator类的源码(可以看出实现过程差不多,但next返回的元素不一样,遍历得到的结果也就不一样)
//遍历得到所有的key
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() { return nextNode().key; }
}
//遍历得到所有的值
final class ValueIterator extends HashIterator
implements Iterator<V> {
public final V next() { return nextNode().value; }
}
//遍历得到所有的节点(保存key和value)
final class EntryIterator extends HashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() { return nextNode(); }
}
然后再看一下会有哪些方法返回这些类的对象:
//这个是HashMap的方法,它可以得到EntrySet的实例
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}
final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
//这个类得到了EntryIterator的实例
public final Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator();
}
public final boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
//这个getKey()是Map接口的嵌套Entry接口定义的方法: K getKey();
//这些看似是覆盖的方法,这里就不详细讲了
Object key = e.getKey();
Node<K,V> candidate = getNode(hash(key), key);
return candidate != null && candidate.equals(e);
}
public final boolean remove(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Object value = e.getValue();
return removeNode(hash(key), key, value, true, true) != null;
}
return false;
}
=======================================================
//这个是HashMap的方法,它可以得到KeySet的实例
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks;
}
final class KeySet extends AbstractSet<K> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
//得到KeyIterator的实例
public final Iterator<K> iterator() { return new KeyIterator(); }
public final boolean contains(Object o) { return containsKey(o); }
public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;
}
public final Spliterator<K> spliterator() {
return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super K> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
================================================================
//这个是HashMap的方法,它可以得到Values的实例
public Collection<V> values() {
Collection<V> vs = values;
if (vs == null) {
vs = new Values();
values = vs;
}
return vs;
}
final class Values extends AbstractCollection<V> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
//得到ValueIterator的实例
public final Iterator<V> iterator() { return new ValueIterator(); }
public final boolean contains(Object o) { return containsValue(o); }
public final Spliterator<V> spliterator() {
return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super V> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.value);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
Map和Collection接口对于迭代器的想法有点不同,Map没有规定要实现迭代器方法iterator(),
而Collection在接口明确的定义了这个iterator(),需要子类去实现。