手撕HashMap迭代器

HashMap 迭代器非常容易理解,先看类关系图:

HashMap迭代器类结构图

这三个迭代器,分别对应 entrySetkeySetvalues 方法返回对象的迭代器。这三个方法分别返回 EntrySetKeySetValues 对象,这三个类均定义在 HashMap 中。

迭代器

迭代器的主要实现都在 HashIterator 这个抽象类中:

	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

        HashIterator() {
            expectedModCount = modCount;
            Node<K,V>[] t = table;
            current = next = null;
            index = 0;
            // 初始化 next
            if (t != null && size > 0) { // advance to first entry
                do {} while (index < t.length && (next = t[index++]) == null);
            }
        }

        public final boolean hasNext() {
            return next != null;
        }

        final Node<K,V> nextNode() {
            Node<K,V>[] t;
            Node<K,V> e = next;
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if (e == null)
                throw new NoSuchElementException();
            // 优先遍历箱,再遍历表
            /*
            * 这样的写法真的很有趣。简单两行,就完成了所想做的事,如果换成自己来写,没有十行代码是搞不
            * 定的,不过 (next = (current = e).next) == null 这种在表达式中再去赋值,看起来
            * 真的很不适应。
            */
            if ((next = (current = e).next) == null && (t = table) != null) {
                do {} while (index < t.length && (next = t[index++]) == null);
            }
            return e;
        }

        public final void remove() {
            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;
        }
    }

虽然 HashIterator 并没有直接实现 Iterator 接口,但其方法签名则完全是 Iterator 接口的(除了 nextNode 方法)。

下面再来看看,抽象类的具体实现:

    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; }
    }

    final class EntryIterator extends HashIterator
        implements Iterator<Map.Entry<K,V>> {
        public final Map.Entry<K,V> next() { return nextNode(); }
    }

实现非常简单,完全依赖迭代器的元素进行操作,具体实现都已经在 nextNode 方法中完成。

总结

迭代器的实现还是比较简单的。HashMap 本身并没有返回迭代器方法,而是在选择返回值或者 key 的方法时,重写了返回的 Set 对象或者 Collection 对象中的 Iterator

需要理解的是 HashMap 是如何去设计的,而且在源码中,发现大量在表达式中赋值的写法。这样的写法或许更简洁,至于可读性就智者见智了。


推荐博文

手撕Java类HashMap
手撕HashMap红黑树

我与风来


认认真真学习,做思想的产出者,而不是文字的搬运工
错误之处,还望指出

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值