關於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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM