HashMap如何在内部工作

时间:2014-08-06 15:51:52

标签: collections hashmap

HashMap objHashMap = new HashMap();

objHashMap.put("key1", "Value1");
objHashMap.put("key1", "Value2");

System.out.println(objHashMap.get("key1"));

以上代码显示“Value2”的方法和原因

2 个答案:

答案 0 :(得分:2)

检查this

/**
* Associates the specified value with the specified key in this map. If the
* map previously contained a mapping for the key, the old value is
* replaced.
*
* @param key
*            key with which the specified value is to be associated
* @param value
*            value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or <tt>null</tt>
*         if there was no mapping for <tt>key</tt>. (A <tt>null</tt> return
*         can also indicate that the map previously associated
*         <tt>null</tt> with <tt>key</tt>.)
*/
public V put(K key, V value) {
    if (key == null)
    return putForNullKey(value);
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    for (Entry<K , V> e = table[i]; e != null; e = 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;
        }
    }

    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

让我们逐一记下这些步骤:

1)首先,检查密钥对象是否为空。如果key为null,则值存储在table [0]位置。因为null的哈希码始终为0。

2)然后在下一步中,通过调用其hashCode()方法,使用密钥的哈希码计算哈希值。此哈希值用于计算用于存储Entry对象的数组中的索引。 JDK设计者很好地假设可能有一些写得不好的hashCode()函数可以返回非常高或低的哈希码值。为了解决这个问题,他们引入了另一个hash()函数,并将对象的哈希代码传递给这个hash()函数,以使哈希值在数组索引大小的范围内。

3)现在调用indexFor(hash,table.length)函数来计算存储Entry对象的精确索引位置。

4)这是主要部分。现在,我们知道两个不相等的对象可以具有相同的哈希码值,两个不同的对象将如何存储在相同的阵列位置[称为桶]。 答案是LinkedList。如果你还记得,Entry类有一个属性“next”。此属性始终指向链中的下一个对象。这正是LinkedList的行为。

因此,在发生冲突的情况下,Entry对象以LinkedList形式存储。当一个Entry对象需要存储在特定的索引中时,HashMap会检查是否已经有一个条目?如果没有条目,则Entry对象存储在此位置。

如果已经有一个对象坐在计算索引上,则会检查其下一个属性。如果为null,则当前Entry对象成为LinkedList中的下一个节点。如果next变量不为null,则执行procedure直到next被计算为null。

如果我们使用之前输入的相同键添加另一个值对象,该怎么办?从逻辑上讲,它应该替换旧的值。怎么做的?好吧,在确定Entry对象的索引位置之后,在计算索引上迭代LinkedList时,HashMap为每个Entry对象调用key对象的方法。 LinkedList中的所有这些Entry对象都具有类似的哈希码,但equals()方法将测试真正的相等性。如果key.equals(k)为true,则两个键都被视为相同的键对象。这将导致仅在Entry对象中替换值对象。

通过这种方式,HashMap可以确保密钥的唯一性。

答案 1 :(得分:1)

因为哈希映射只存储每​​个值的唯一键,这意味着你不能在其中放入2个具有相同名称的键,当你这样做时,你将覆盖该键的值,所以如果你想存储2您需要在其中存储两个不同的键的不同值。

HashMap objHashMap = new HashMap();
objHashMap.put("key1", "Value1");
objHashMap.put("key2", "Value2"); //CHANGED THIS KEY to "key2"

System.out.println(objHashMap.get("key1"));