• 遍历map的四种方法及Map.entry详解


    Map.entrySet() 这个方法返回的是一个Set>,Map.Entry 是Map中的一个接口,他的用途是表示一个映射项(里面有Key和Value),而Set>表示一个映射项的Set。Map.Entry里有相应的getKey和getValue方法,即JavaBean,让我们能够从一个项中取出Key和Value。

    下面是遍历Map的四种方法:

    public static void main(String[] args) { ? ? ? Map map = new HashMap(); ? map.put("1", "value1"); ? map.put("2", "value2"); ? map.put("3", "value3"); ?? ? //第一种:普遍使用,二次取值 ? System.out.println("通过Map.keySet遍历key和value:"); ? for (String key : map.keySet()) { ? ?System.out.println("key= "+ key + " and value= " + map.get(key)); ? } ?? ? //第二种 ? System.out.println("通过Map.entrySet使用iterator遍历key和value:"); ? Iterator> it = map.entrySet().iterator(); ? while (it.hasNext()) { ? ?Map.Entry entry = it.next(); ? ?System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); ? } ?? ? //第三种:推荐,尤其是容量大时 ? System.out.println("通过Map.entrySet遍历key和value"); ? for (Map.Entry entry : map.entrySet()) { ? ?System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); ? } ? ? //第四种 ? System.out.println("通过Map.values()遍历所有的value,但不能遍历key"); ? for (String v : map.values()) { ? ?System.out.println("value= " + v); ? } ?}

    下面是HashMap的源代码:

    首先HashMap的底层实现用的时候一个Entry数组

    java] view plain copy
    
      /** 
         * The table, resized as necessary. Length MUST Always be a power of two. 
         */  
        transient Entry[] table; //声明了一个数组  
       ........  
       public HashMap() {  
            this.loadFactor = DEFAULT_LOAD_FACTOR;  
            threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);  
            table = new Entry[DEFAULT_INITIAL_CAPACITY];//初始化数组的大小为DEFAULT_INITIAL_CAPACITY(这里是16)  
            init();  
        }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    再来看一下Entry是在什么地方定义的,继续上源码,我们在HashMap的源码的674行发现了它的定义,原来他是HashMap的一个内部类,并且实现了Map.Entry接口,以下有些地方是转载[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QILwOhMi-1661912591760)(http://static.blog.csdn.net/xheditor/xheditor_emot/default/quiet.gif)]

    static class Entry implements Map.Entry {  
        final K key;  
        V value;  
        Entry next;  
        final int hash;  
      
        /** 
         * Creates new entry. 
         */  
        Entry(int h, K k, V v, Entry n) {  
            value = v;  
            next = n;  
            key = k;  
            hash = h;  
        }  
      
        public final K getKey() {  
            return key;  
        }  
      
        public final V getValue() {  
            return value;  
        }  
      
        public final V setValue(V newValue) {  
     V oldValue = value;  
            value = newValue;  
            return oldValue;  
        }  
      
        public final boolean equals(Object o) {  
            if (!(o instanceof Map.Entry))  
                return false;  
            Map.Entry e = (Map.Entry)o;  
            Object k1 = getKey();  
            Object k2 = e.getKey();  
            if (k1 == k2 || (k1 != null && k1.equals(k2))) {  
                Object v1 = getValue();  
                Object v2 = e.getValue();  
                if (v1 == v2 || (v1 != null && v1.equals(v2)))  
                    return true;  
            }  
            return false;  
        }  
      
        public final int hashCode() {  
            return (key==null   ? 0 : key.hashCode()) ^  
                   (value==null ? 0 : value.hashCode());  
        }  
      
        public final String toString() {  
            return getKey() + "=" + getValue();  
        }  
      
        /** 
         * This method is invoked whenever the value in an entry is 
         * overwritten by an invocation of put(k,v) for a key k that's already 
         * in the HashMap. 
         */  
        void recordAccess(HashMap m) {  
        }  
      
        /** 
         * This method is invoked whenever the entry is 
         * removed from the table. 
         */  
        void recordRemoval(HashMap m) {  
        }  
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    既然这样那我们再看一下Map.Entry这个接口是怎么定义的,原来他是Map的一个内部接口并且定义了一些方法???????

      interface Entry {  
        /** 
     * Returns the key corresponding to this entry. 
     * 
     * @return the key corresponding to this entry 
            * @throws IllegalStateException implementations may, but are not 
            *         required to, throw this exception if the entry has been 
            *         removed from the backing map. 
     */  
    K getKey();  
      
        /** 
     * Returns the value corresponding to this entry.  If the mapping 
     * has been removed from the backing map (by the iterator's 
     * remove operation), the results of this call are undefined. 
     * 
     * @return the value corresponding to this entry 
            * @throws IllegalStateException implementations may, but are not 
            *         required to, throw this exception if the entry has been 
            *         removed from the backing map. 
     */  
    V getValue();  
      
        /** 
     * Replaces the value corresponding to this entry with the specified 
     * value (optional operation).  (Writes through to the map.)  The 
     * behavior of this call is undefined if the mapping has already been 
     * removed from the map (by the iterator's remove operation). 
     * 
            * @param value new value to be stored in this entry 
            * @return old value corresponding to the entry 
            * @throws UnsupportedOperationException if the put operation 
            *         is not supported by the backing map 
            * @throws ClassCastException if the class of the specified value 
            *         prevents it from being stored in the backing map 
            * @throws NullPointerException if the backing map does not permit 
            *         null values, and the specified value is null 
            * @throws IllegalArgumentException if some property of this value 
            *         prevents it from being stored in the backing map 
            * @throws IllegalStateException implementations may, but are not 
            *         required to, throw this exception if the entry has been 
            *         removed from the backing map. 
            */  
    V setValue(V value);  
      
    /** 
     * Compares the specified object with this entry for equality. 
     * Returns true if the given object is also a map entry and 
     * the two entries represent the same mapping.  More formally, two 
     * entries e1 and e2 represent the same mapping 
     * if
     
            *     (e1.getKey()==null ? 
            *      e2.getKey()==null : e1.getKey().equals(e2.getKey()))  && 
            *     (e1.getValue()==null ? 
            *      e2.getValue()==null : e1.getValue().equals(e2.getValue())) 
            * 
    * This ensures that the equals method works properly across * different implementations of the Map.Entry interface. * * @param o object to be compared for equality with this map entry * @return true if the specified object is equal to this map * entry */ boolean equals(Object o); /** * Returns the hash code value for this map entry. The hash code * of a map entry e is defined to be:
     
     *     (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^ 
     *     (e.getValue()==null ? 0 : e.getValue().hashCode()) 
            * 
    * This ensures that e1.equals(e2) implies that * e1.hashCode()==e2.hashCode() for any two Entries * e1 and e2, as required by the general * contract of Object.hashCode. * * @return the hash code value for this map entry * @see Object#hashCode() * @see Object#equals(Object) * @see #equals(Object) */ int hashCode(); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    看到这里的时候大伙儿估计都明白得差不多了为什么HashMap为什么要选择Entry数组来存放key-value对了吧,因为Entry实现的Map.Entry接口里面定义了getKey(),getValue(),setKey(),setValue()等方法相当于一个javaBean,对键值对进行了一个封装便于后面的操作,从这里我们其实也可以联想到不光是HashMap,譬如LinkedHashMap,TreeMap 等继承自map的容器存储key-value对都应该使用的是Entry只不过组织Entry的形式不一样,HashMap用的是数组加链表的形式,LinkedHashMap用的是链表的形式,TreeMap应该使用的二叉树的形式,不信的话上源码

    LinkedHashMap:???????

    /** 
        * The head of the doubly linked list. 
        */  
    /定义了链头  
       private transient Entry header;  
    
    • 1
    • 2
    • 3
    • 4
    • 5

    初始化链表的方法:

    void init() {  
        header = new Entry(-1, null, null, null);  
        header.before = header.after = header;  
    }  
    
    • 1
    • 2
    • 3
    • 4

    TreeMap:

    [java] view plain copy
    //定义根节点  
     private transient Entry root = null;  
    
    • 1
    • 2
    • 3

    再看他的put方法,是不是很面熟(二叉排序树的插入操作)???????

    public V put(K key, V value) {  
        Entry t = root;  
        if (t == null) {  
     // TBD:  
     // 5045147: (coll) Adding null to an empty TreeSet should  
     // throw NullPointerException  
     //  
     // compare(key, key); // type check  
            root = new Entry(key, value, null);  
            size = 1;  
            modCount++;  
            return null;  
        }  
        int cmp;  
        Entry parent;  
        // split comparator and comparable paths  
        Comparator cpr = comparator;  
        if (cpr != null) {  
            do {  
                parent = t;  
                cmp = cpr.compare(key, t.key);  
                if (cmp < 0)  
                    t = t.left;  
                else if (cmp > 0)  
                    t = t.right;  
                else  
                    return t.setValue(value);  
            } while (t != null);  
        }  
        else {  
            if (key == null)  
                throw new NullPointerException();  
            Comparable k = (Comparable) key;  
            do {  
                parent = t;  
                cmp = k.compareTo(t.key);  
                if (cmp < 0)  
                    t = t.left;  
                else if (cmp > 0)  
                    t = t.right;  
                else  
                    return t.setValue(value);  
            } while (t != null);  
        }  
        Entry e = new Entry(key, value, parent);  
        if (cmp < 0)  
            parent.left = e;  
        else  
            parent.right = e;  
        fixAfterInsertion(e);  
        size++;  
        modCount++;  
        return null;  
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    ok,明白了各种Map的底层存储key-value对的方式后,再来看看如何遍历map吧,这里用HashMap来演示吧

    Map提供了一些常用方法,如keySet()、entrySet()等方法**,keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。**

    so,很容易写出如下的遍历代码???????

    [java] view plain copy
    1.  Map map = new HashMap();  
      
             Irerator iterator = map.entrySet().iterator();  
      
             while(iterator.hasNext()) {  
      
                     Map.Entry entry = iterator.next();  
      
                     Object key = entry.getKey();  
      
                     //  
      
             }  
      
         2.Map map = new HashMap();   
      
             Set  keySet= map.keySet();  
      
             Irerator iterator = keySet.iterator;  
      
             while(iterator.hasNext()) {  
      
                     Object key = iterator.next();  
      
                     Object value = map.get(key);  
      
                     //  
      
             }  
    另外,还有一种遍历方法是,单纯的遍历value值,Map有一个values方法,返回的是value的Collection集合。通过遍历collection也可以遍历value,如
    [java] view plain copy
    Map map = new HashMap();  
      
    Collection c = map.values();  
      
    Iterator iterator = c.iterator();  
      
    while(iterator.hasNext()) {  
      
           Object value = iterator.next();   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    原文转至:https://blog.csdn.net/kyi_zhu123/article/details/52769469

    )

  • 相关阅读:
    MySQL8.0优化 - ER模型、数据表的设计原则
    【JVM】synchronized与锁升级
    ai语音机器人工作的原理流程电销机器人部署
    贼简单的Android计时工具,老铁,还不试用起来。
    μC/OS-II---互斥信号量管理1(os_mutex.c)
    网络基本类型
    编译原理实验一:源程序的预处理及词法分析程序的设计与实现(python)
    .360勒索病毒数据恢复|金蝶、用友、管家婆、OA、速达、ERP等软件数据库恢复
    面向对象编程(高级部分)——代码块
    Java-IDEA-类注释快捷键
  • 原文地址:https://blog.csdn.net/m0_67394360/article/details/126618623