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;
    }

从上面这段源码分析可知,数据的存储过程如下:
HashMap的一点理解

因为我重新了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之后数据的存储如下:
HashMap的一点理解

如果把上面的例子稍微修改一下,让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

数据的存储过程如下:

HashMap的一点理解

Debug之后数据的存储如下:

 HashMap的一点理解

以上。