HashMap中通过keySet遍历的顺序

Posted hanzhengjie

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(); }
        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中ketSet的方法,以及KeySet类的源码

当第一次调用keySet时会创建一个对象,当遍历时会创建KeyIterator对象;这个对象是一个hashmap内部类

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

继续调用HashIterator的nextNode()方法;HashIterator也是HashMap的内部类

 

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方法是按照数组的index从小到大遍历的
        HashIterator() {
            expectedModCount = modCount;
            Node<K,V>[] t = table;//存储node的数组;
            current = next = null;
            index = 0;
            if (t != null && size > 0) { // advance to first entry 为next节点赋值
                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();
            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;
        }
    }

 modCount != expectedModCount 这个判断的存在是为了不允许我们在遍历时通过hashmap的方法进行添加删除

modCount和expectedModCount 记录了map的修改次数

当通过haspmap修改时 HashIterator内部的expectedModCount 不会被修改;

 

 

 


       

 

以上是关于HashMap中通过keySet遍历的顺序的主要内容,如果未能解决你的问题,请参考以下文章

Java HashMap 遍历方式探讨

Java HashMap keyset()按排序顺序迭代[重复]

HashMap的两种遍历方式

java hashmap常见用法

遍历HashMap的几种常用方法

java_HashMap的遍历方法_4种