HashMap的一点理解
先看看一个例子:
1 import java.util.HashMap;
2 import java.util.Map;
3
4 class A {
5
6 @Override
7 public int hashCode() {
8 return 1;
9 }
10
11 @Override
12 public boolean equals(Object obj) {
13 return true;
14 }
15 }
16
17 public class BeanTest {
18
19 public static void main(String[] args) {
20 A a = new A();
21 A b = new A();
22 A c = new A();
23 A d = new A();
24 Map<A, Integer> map = new HashMap<A, Integer>();
25 map.put(a, 1);
26 map.put(b, 2);
27 map.put(c, 3);
28 map.put(d, 4);
29
30 System.out.println(map.size());
31 System.out.println(map.get(a));
32 }
33 }
输出结果:
1 1
2 4
为什么会出现这样的结果呢,分析一下源码:
@SuppressWarnings("unchecked")
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
if (table[i] instanceof Entry) {
// Bin contains ordinary Entries. Search for key in the linked list
// of entries, counting the number of entries. Only check for
// TreeBin conversion if the list size is >= TREE_THRESHOLD.
// (The conversion still may not happen if the table gets resized.)
int listSize = 0;
Entry<K,V> e = (Entry<K,V>) table[i];
for (; e != null; e = (Entry<K,V>)e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
listSize++;
}
// Didn't find, so fall through and call addEntry() to add the
// Entry and check for TreeBin conversion.
checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
} else if (table[i] != null) {
TreeBin e = (TreeBin)table[i];
TreeNode p = e.putTreeNode(hash, key, value, null);
if (p == null) { // putTreeNode() added a new node
modCount++;
size++;
if (size >= threshold) {
resize(2 * table.length);
}
return null;
} else { // putTreeNode() found an existing node
Entry<K,V> pEntry = (Entry<K,V>)p.entry;
V oldVal = pEntry.value;
pEntry.value = value;
pEntry.recordAccess(this);
return oldVal;
}
}
modCount++;
addEntry(hash, key, value, i, checkIfNeedTree);
return null;
}
从上面这段源码分析可知,数据的存储过程如下:
因为我重新了hashcode()和equal()函数,如果hashcode相同并且equal比较也相同的话,那么这个值就会被替换,具体的逻辑就是下面这段代码。
1 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
2 V oldValue = e.value;
3 e.value = value;
4 e.recordAccess(this);
5 return oldValue;
6 }
Debug之后数据的存储如下:
如果把上面的例子稍微修改一下,让equals的返回值为false或者去掉equals方法结果又是怎么样的呢?
1 import java.util.HashMap;
2 import java.util.Map;
3
4 class A {
5
6 @Override
7 public int hashCode() {
8 return 1;
9 }
10
11 @Override
12 public boolean equals(Object obj) {
13 return false;
14 }
15 }
16
17 public class BeanTest {
18
19 public static void main(String[] args) {
20 A a = new A();
21 A b = new A();
22 A c = new A();
23 A d = new A();
24 Map<A, Integer> map = new HashMap<A, Integer>();
25 map.put(a, 1);
26 map.put(b, 2);
27 map.put(c, 3);
28 map.put(d, 4);
29
30 System.out.println(map.size());
31 System.out.println(map.get(a));
32 }
33 }
输出结果:
4
1
数据的存储过程如下:
Debug之后数据的存储如下:
以上。