转自---https://blog.csdn.net/gm371200587/article/details/82108372
Map.entrySet() 这个方法返回的是一个Set
下面是遍历Map的四种方法:
public static void main(String[] args) {
Map
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
while (it.hasNext()) {
Map.Entry
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry
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);
}
}
Map.entrySet() 这个方法返回的是一个Set
下面是遍历Map的四种方法:
public static void main(String[] args) {
Map
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
while (it.hasNext()) {
Map.Entry
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry
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
-
"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();
-
}
再来看一下Entry是在什么地方定义的,继续上源码,我们在HashMap的源码的674行发现了它的定义,原来他是HashMap的一个内部类,并且实现了Map.Entry接口,以下有些地方是转载
-
static class Entry<K,V> implements Map.Entry<K,V> {
-
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) { -
}
-
}
既然这样那我们再看一下Map.Entry这个接口是怎么定义的,原来他是Map的一个内部接口并且定义了一些方法
-
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
-
* 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();
-
}
看到这里的时候大伙儿估计都明白得差不多了为什么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;
初始化链表的方法:
-
void init() {
-
header = new Entry
(- 1, null, null, null); -
header.before = header.after = header;
-
}
TreeMap:
-
[java] view plain copy
-
//定义根节点
-
private transient Entry
root = null;
再看他的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 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
e = new Entry (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();