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的四种方法:
- public static void main(String[] args) {
- Map<String, String> map = new HashMap<String, String>();
- 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<Map.Entry<String, String>> it = map.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<String, String> entry = it.next();
- System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
- }
- //第三种:推荐,尤其是容量大时
- System.out.println("通过Map.entrySet遍历key和value");
- for (Map.Entry<String, String> 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
- <pre name="code" class="java"> /**
- * 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();
- }</pre><br>
再来看一下Entry是在什么地方定义的,继续上源码,我们在HashMap的源码的674行发现了它的定义,原来他是HashMap的一个内部类,并且实现了Map.Entry接口,以下有些地方是转载
- static class Entry<K,V> implements Map.Entry<K,V> {
- final K key;
- V value;
- Entry<K,V> next;
- final int hash;
- /**
- * Creates new entry.
- */
- Entry(int h, K k, V v, Entry<K,V> 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<K,V> m) {
- }
- /**
- * This method is invoked whenever the entry is
- * removed from the table.
- */
- void recordRemoval(HashMap<K,V> m) {
- }
- }
- interface Entry<K,V> {
- /**
- * 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
- * <tt>remove</tt> 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 <tt>remove</tt> operation).
- *
- * @param value new value to be stored in this entry
- * @return old value corresponding to the entry
- * @throws UnsupportedOperationException if the <tt>put</tt> 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 <tt>true</tt> if the given object is also a map entry and
- * the two entries represent the same mapping. More formally, two
- * entries <tt>e1</tt> and <tt>e2</tt> represent the same mapping
- * if<pre>
- * (e1.getKey()==null ?
- * e2.getKey()==null : e1.getKey().equals(e2.getKey())) &&
- * (e1.getValue()==null ?
- * e2.getValue()==null : e1.getValue().equals(e2.getValue()))
- * </pre>
- * This ensures that the <tt>equals</tt> method works properly across
- * different implementations of the <tt>Map.Entry</tt> interface.
- *
- * @param o object to be compared for equality with this map entry
- * @return <tt>true</tt> 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 <tt>e</tt> is defined to be: <pre>
- * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^
- * (e.getValue()==null ? 0 : e.getValue().hashCode())
- * </pre>
- * This ensures that <tt>e1.equals(e2)</tt> implies that
- * <tt>e1.hashCode()==e2.hashCode()</tt> for any two Entries
- * <tt>e1</tt> and <tt>e2</tt>, as required by the general
- * contract of <tt>Object.hashCode</tt>.
- *
- * @return the hash code value for this map entry
- * @see Object#hashCode()
- * @see Object#equals(Object)
- * @see #equals(Object)
- */
- int hashCode();
- }
看到这里的时候大伙儿估计都明白得差不多了为什么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<K,V> header;
初始化链表的方法:
- void init() {
- header = new Entry<K,V>(-1, null, null, null);
- header.before = header.after = header;
- }
- [java] view plain copy
- //定义根节点
- private transient Entry<K,V> root = null;
- public V put(K key, V value) {
- Entry<K,V> 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<K,V>(key, value, null);
- size = 1;
- modCount++;
- return null;
- }
- int cmp;
- Entry<K,V> parent;
- // split comparator and comparable paths
- Comparator<? super K> 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<? super K> k = (Comparable<? super K>) 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<K,V> e = new Entry<K,V>(key, value, parent);
- if (cmp < 0)
- parent.left = e;
- else
- parent.right = e;
- fixAfterInsertion(e);
- size++;
- modCount++;
- return null;
- }
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();