Map.entry详解

Map.entry详解

 

 https://blog.csdn.net/kyi_zhu123/article/details/52769469

 

   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应该使用的二叉树的形式,不信的话上源码

 

LinkedHashMap:

 

 
  1. /**

  2. * The head of the doubly linked list.

  3. */

  4. /定义了链头

  5. private transient Entry<K,V> header;


初始化链表的方法:

 

 
  1. void init() {

  2. header = new Entry<K,V>(-1, null, null, null);

  3. header.before = header.after = header;

  4. }

 

TreeMap:

 

 
  1. [java] view plain copy

  2. //定义根节点

  3. private transient Entry<K,V> root = null;

 

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

 

 
  1. public V put(K key, V value) {

  2. Entry<K,V> t = root;

  3. if (t == null) {

  4. // TBD:

  5. // 5045147: (coll) Adding null to an empty TreeSet should

  6. // throw NullPointerException

  7. //

  8. // compare(key, key); // type check

  9. root = new Entry<K,V>(key, value, null);

  10. size = 1;

  11. modCount++;

  12. return null;

  13. }

  14. int cmp;

  15. Entry<K,V> parent;

  16. // split comparator and comparable paths

  17. Comparator<? super K> cpr = comparator;

  18. if (cpr != null) {

  19. do {

  20. parent = t;

  21. cmp = cpr.compare(key, t.key);

  22. if (cmp < 0)

  23. t = t.left;

  24. else if (cmp > 0)

  25. t = t.right;

  26. else

  27. return t.setValue(value);

  28. } while (t != null);

  29. }

  30. else {

  31. if (key == null)

  32. throw new NullPointerException();

  33. Comparable<? super K> k = (Comparable<? super K>) key;

  34. do {

  35. parent = t;

  36. cmp = k.compareTo(t.key);

  37. if (cmp < 0)

  38. t = t.left;

  39. else if (cmp > 0)

  40. t = t.right;

  41. else

  42. return t.setValue(value);

  43. } while (t != null);

  44. }

  45. Entry<K,V> e = new Entry<K,V>(key, value, parent);

  46. if (cmp < 0)

  47. parent.left = e;

  48. else

  49. parent.right = e;

  50. fixAfterInsertion(e);

  51. size++;

  52. modCount++;

  53. return null;

  54. }


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

 

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

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

 

 
  1. [java] view plain copy

  2. 1. Map map = new HashMap();

  3.  
  4. Irerator iterator = map.entrySet().iterator();

  5.  
  6. while(iterator.hasNext()) {

  7.  
  8. Map.Entry entry = iterator.next();

  9.  
  10. Object key = entry.getKey();

  11.  
  12. //

  13.  
  14. }

  15.  
  16. 2.Map map = new HashMap();

  17.  
  18. Set keySet= map.keySet();

  19.  
  20. Irerator iterator = keySet.iterator;

  21.  
  22. while(iterator.hasNext()) {

  23.  
  24. Object key = iterator.next();

  25.  
  26. Object value = map.get(key);

  27.  
  28. //

  29.  
  30. }

  31. 另外,还有一种遍历方法是,单纯的遍历value值,Map有一个values方法,返回的是value的Collection集合。通过遍历collection也可以遍历value,如

  32. [java] view plain copy

  33. Map map = new HashMap();

  34.  
  35. Collection c = map.values();

  36.  
  37. Iterator iterator = c.iterator();

  38.  
  39. while(iterator.hasNext()) {

  40.  
  41. Object value = iterator.next();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值