美文网首页
HashMap源码浅析(三):迭代器Iterator

HashMap源码浅析(三):迭代器Iterator

作者: 小川君 | 来源:发表于2018-09-14 00:28 被阅读0次

    KeySet

    我们在遍历HashMap的时候会用到keySet()获取到当前HashMap的key值的一个Set集合

        public Set<K> keySet() {
            Set<K> ks = keySet;
            if (ks == null) {
                ks = new KeySet();
                keySet = ks;
            }
            return ks;
        }
    

    可以看到直接创建了一个KeySet对象,final class KeySet extends AbstractSet<K>,KeySet继承于AbstractSet
    KeySet有几个方法:

    size 返回当前HashMap的元素数量
    clear 情况当前HashMap的元素
    iterator 返回一个KeyIterator对象,用于遍历key值
    contains 判断当前HashMap中是否包含有指定的key值
    remove删除指定key值
    forEach 遍历集合,每遍历一次返回一个key值

    我们先来看iterator()
    HashMap#KeySet#iterator():

            public final Iterator<K> iterator()     {
                return new KeyIterator(); 
            }
            
            final class KeyIterator extends HashIterator implements Iterator<K> {
            
                public final K next() { return nextNode().key; }
                
        }
    

    KeyIterator继承于HashIteratorIterator,只有一个next()

    KeyIterator

    KeyIterator中的属性:

    next 代表当前节点的下一个节点
    current 代表当前节点
    expectedModCount 代表修改次数 遍历期间不能对集合进行操作,否则expectedModeCount不一致会抛出异常
    index 当前节点的下标

    keyIterator中的方法

    hasNext() 判断当前节点是否还有下一节点,即当前节点是否是尾节点
    nextNode() 返回下一节点的node
    remove() 删除当前节点

    我们先来看构造器
    HashMap#HashIterator#HashIterator():

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

    构造器中对属性进行了初始化,并通过while循环,得到数组中的第一个不为空的元素下标以及值,并将此元素值赋给next
    HashMap#HashIterator#hasNext():

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

    hasNext()判断当前元素是否有下个节点值,首次调用的话,next为构造器中首次遍历到的值
    HashMap#HashIterator#nextNode():

            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();
                if ((next = (current = e).next) == null && (t = table) != null) {
                    do {} while (index < t.length && (next = t[index++]) == null);
                }
                return e;
            }
    

    nextNode()获取遍历到的当前节点,也可以理解为hasNext()所判断的下一节点,主要是看最后一个判断,e为当前要返回的节点,获取e的下一节点,并赋值给next,如果此时的next为空,则说明当前链表已经遍历完毕,那么进入判断体,开始遍历下一个数组桶中的链表,并将此链表的头结点赋值给next;
    remove()比较简单这里就不多说了。
    说到这里我们结合KeySet整体总结一遍流程:

            HashMap<String,String> hashMap = new HashMap<>();
            hashMap.put("w","c");
            hashMap.put("a","h");
            hashMap.put("n","u");
            hashMap.put("g","a");
            hashMap.put("c","n");
            Iterator<String> iterator = hashMap.keySet().iterator();
            while (iterator.hasNext()){
                Log.i("chuan", "onResume: " + iterator.next());
            }
    

    上面是通过KeySet对集合进行的遍历
    首先我们通过keySet()获取到一个Set对象(虽然Set内部也是通过HashMap实现的,但是这里只是用到了HashMap的存储功能,并没有用到迭代器,否则就陷入了先有鸡还是先有蛋的死循环中)

        public Set<K> keySet() {
            Set<K> ks = keySet;
            if (ks == null) {
                ks = new KeySet();
                keySet = ks;
            }
            return ks;
        }
        
        public final Iterator<K> iterator()     { return new KeyIterator(); }
    

    然后通过KeySet中的iterator()获取到Iterator对象,

            final class KeyIterator extends HashIterator
                implements Iterator<K> {
                public final K next() { return nextNode().key; }
            }
        
            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();
                if ((next = (current = e).next) == null && (t = table) != null) {
                    do {} while (index < t.length && (next = t[index++]) == null);
                }
                return e;
            }
    

    最后通过HashIteratorhashNext()nextNode()获取到下一节点
    其实继承HashIterator的还有两个类,分别是获取valuenodeValueIteratorEntryIterator,逻辑都一样,都是先获取到指定的节点node,然后在分别获取key,value或是node

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

    相关文章

      网友评论

          本文标题:HashMap源码浅析(三):迭代器Iterator

          本文链接:https://www.haomeiwen.com/subject/gfoxgftx.html