hashmap 遍历_HashMap之深入理解keySet、values、entrySet

HashMap遍历的方式

    Map map = new HashMap<>();    //1、for循环遍历key    System.out.println("通过Map.keySet遍历key和value:");    for (String key: map.keySet()){        System.out.println("key:"+key+" value:"+map.get(key));    }    //2、for循环遍历value    System.out.println("通过Map.values()遍历所有的value,但ey");    for(Object v:map.values())    {        System.out.println("value:"+v);    }    //3、for循环遍历entrySet    System.out.println("通过Map.entrySet遍历key和value");    for(Map.Entry entry: map.entrySet())    {        System.out.println("Key: "+ entry.getKey()+ " Va"+entry.getValue());    }    //4、iterator    System.out.println("通过Map.entrySet使用iterator遍历key和va");    Iterator> iterator = map.entrySet().iterator();    while(iterator.hasNext()){        Map.Entry entry = iterator.next();        System.out.println("key:"+entry.getKey()+" value:"+entry.getValue());    }

在遍历HashMap的时候:

    Set setStrings = map.keySet()    for (String key: setStrings){        System.out.println("key:"+key+" value:"+map.get(key));    }

但是keySet()是如何获取到HashMap的所有的key呢?

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

其中keySet、values是AbstractMap中声明的变量:

    transient Set        keySet;    transient Collection values;

调用map.keySet()时,会判断ks是否为空,然后调用new KeySet(),keySet()方法返回一个引用,这个引用指向了HashMap的一个内部类KeySet类:

 final class KeySet extends AbstractSet {        public final int size()                 { return size; }        public final void clear()               { HashMap.this.clear(); }        public final Iterator 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 spliterator() {            return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);        }        public final void forEach(Consumer super K> action) {            Node[] 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 e = tab[i]; e != null; e = e.next)                        action.accept(e.key);                }                if (modCount != mc)                    throw new ConcurrentModificationException();            }        }    }

此内部类继承了AbstractSet,此内部类初始化迭代器产生一个迭代器对象KeyIterator:

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

在使用增强for循环遍历map.keySet()时,就是调用的KeyIterator.next()方法。KeyIterator类继承了HashIterator迭代器:

abstract class HashIterator {        Node next;        // next entry to return        Node current;     // current entry        int expectedModCount;  // for fast-fail        int index;             // current slot        HashIterator() {            expectedModCount = modCount;            Node[] 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);            }        }        public final boolean hasNext() {            return next != null;        }        final Node nextNode() {            Node[] t;            Node 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 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迭代器初始化拿到了next指向map中的第一个元素。当使用keySet集合遍历key时,其实是使用迭代器KeyIterator迭代每个节点的key。

问题:在使用增强for循环遍历map.keySet()时,为什么调用的KeyIterator.next()?对使用增强for循环反编译发现:

    Set keys = map.keySet();    Iterator iterator = keys.iterator()    while(iterator.hasNext()) {        String key = (String)iterator.next();        System.out.println("key:" + key + " value:" (String)map.get(key));    }

增强for循环根本还是iterator()而KeySet定义的iterator()返回值为new KeyIterator(),因此在使用增强for循环遍历map.keySet()时,调用的是KeyIterator.next()。

总结:

  1. keySet和values和entrySet本质既然一样,就可以通过封装其相同的部分(也就是这里的HashIterator),再各自实现最重要的next方法。
  2. keySet()方法返回一个内部引用,并指向一个内部类对象,该内部类重写了迭代器方法,当在增强for循环时才调用,并从外部类的table中取值。
6c75339ae5831d882f67ddfcc8b453b9.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于HashMap遍历,有几种常用的方法可以实现: 1. 使用EntrySet遍历:通过调用HashMapentrySet()方法获取到HashMap中所有的键值对组成的Set集合,然后通过遍历Set集合中的每个元素,来获取键和值。 ```java HashMap<String, Integer> map = new HashMap<>(); // 添加键值对 map.put("A", 1); map.put("B", 2); map.put("C", 3); // 使用entrySet遍历 for (Map.Entry<String, Integer> entry : map.entrySet()) { String key = entry.getKey(); Integer value = entry.getValue(); System.out.println("Key: " + key + ", Value: " + value); } ``` 2. 使用KeySet遍历:通过调用HashMapkeySet()方法获取到HashMap中所有的键组成的Set集合,然后通过遍历Set集合中的每个键,来获取对应的值。 ```java HashMap<String, Integer> map = new HashMap<>(); // 添加键值对 map.put("A", 1); map.put("B", 2); map.put("C", 3); // 使用keySet遍历 for (String key : map.keySet()) { Integer value = map.get(key); System.out.println("Key: " + key + ", Value: " + value); } ``` 3. 使用Java 8的forEach方法遍历:利用HashMap的forEach方法,可以使用Lambda表达式对每个键值对进行操作。 ```java HashMap<String, Integer> map = new HashMap<>(); // 添加键值对 map.put("A", 1); map.put("B", 2); map.put("C", 3); // 使用forEach遍历 map.forEach((key, value) -> System.out.println("Key: " + key + ", Value: " + value)); ``` 以上是几种常用的HashMap遍历方法,根据具体的需求选择适合的方式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值