HashMap中的迭代器实现与HashSet实现浅析

因为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(),需要子类去实现。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值