• 关于HashMap遍历,为什么要用entry


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

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

     1 public static void main(String[] args) {
     2  
     3  
     4   Map<String, String> map = new HashMap<String, String>();
     5   map.put("1", "value1");
     6   map.put("2", "value2");
     7   map.put("3", "value3");
     8   
     9   //第一种:普遍使用,二次取值
    10   System.out.println("通过Map.keySet遍历key和value:");
    11   for (String key : map.keySet()) {
    12    System.out.println("key= "+ key + " and value= " + map.get(key));
    13   }
    14   
    15   //第二种
    16   System.out.println("通过Map.entrySet使用iterator遍历key和value:");
    17   Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
    18   while (it.hasNext()) {
    19    Map.Entry<String, String> entry = it.next();
    20    System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
    21   }
    22   
    23   //第三种:推荐,尤其是容量大时
    24   System.out.println("通过Map.entrySet遍历key和value");
    25   for (Map.Entry<String, String> entry : map.entrySet()) {
    26    System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
    27   }
    28  
    29   //第四种
    30   System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
    31   for (String v : map.values()) {
    32    System.out.println("value= " + v);
    33   }
    34  }

    下面是HashMap的源代码:

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

     1 java] view plain copy
     2 <pre name="code" class="java">  /** 
     3      * The table, resized as necessary. Length MUST Always be a power of two. 
     4      */  
     5     transient Entry[] table; //声明了一个数组  
     6    ........  
     7    public HashMap() {  
     8         this.loadFactor = DEFAULT_LOAD_FACTOR;  
     9         threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);  
    10         table = new Entry[DEFAULT_INITIAL_CAPACITY];//初始化数组的大小为DEFAULT_INITIAL_CAPACITY(这里是16)  
    11         init();  
    12     }</pre><br>  

    再来看一下Entry是在什么地方定义的,继续上源码,我们在HashMap的源码的674行发现了它的定义,原来他是HashMap的一个内部类,并且实现了Map.Entry接口,

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

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

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

      回归前传,为什么HashMap为什么要选择Entry数组来存放key-value?

      因为Entry实现的Map.Entry接口里面定义了getKey(),getValue(),setKey(),setValue()等方法相当于一个javaBean,对键值对进行了一个封装便于后面的操作,从这里我们其实也可以联想到不光是HashMap,譬如LinkedHashMap,TreeMap 等继承自map的容器存储key-value对都应该使用的是Entry只不过组织Entry的形式不一样,HashMap用的是数组加链表的形式,LinkedHashMap用的是链表的形式,TreeMap应该使用的二叉树的形式。

      keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。

      所以,遍历HashMap一共有开头的四种方法,也不难理解为什么有了keySet(),values(),iterator()还要再使用Entry。

    Over...

    参考:

    1. https://blog.csdn.net/yaomingyang/article/details/78748130
    2. https://blog.csdn.net/kyi_zhu123/article/details/52769469
  • 相关阅读:
    实验三-并发程序 20175201张驰
    20175201 20175215 20175229 实验二 固件程序设计
    20175201 20175215 20175229 实验一 开发环境的熟悉
    #20175201 实验五 网络编程与安全
    云班课选做
    2019-2020-12 20175313 20175328 20175329 实验五 通讯协议设计
    2019-2020-1 20175313 20175328 20175329 实验四 外设驱动程序设计
    2019-2020-1 20175313 20175328 20175329 实验三 并发程序
    20175329&20175313&20175318 2019-2020 《信息安全系统设计基础》实验三
    20175329&20175313&20175318 2019-2020 《信息安全系统设计基础》实验二
  • 原文地址:https://www.cnblogs.com/gjmhome/p/11290327.html
Copyright © 2020-2023  润新知