Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 具有不同哈希值的键是否也映射到HashMap中的同一索引?_Java_Hashmap_Collision - Fatal编程技术网

Java 具有不同哈希值的键是否也映射到HashMap中的同一索引?

Java 具有不同哈希值的键是否也映射到HashMap中的同一索引?,java,hashmap,collision,Java,Hashmap,Collision,查看代码第393行,看起来不同的散列映射到了同一个索引。我知道hashcode用于确定HashMap中要使用的bucket,bucket由一个包含所有具有相同hashcode的条目的链表组成。他们为什么要检查e.hash==hash public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.ha

查看代码第393行,看起来不同的散列映射到了同一个索引。我知道hashcode用于确定HashMap中要使用的bucket,bucket由一个包含所有具有相同hashcode的条目的链表组成。他们为什么要检查
e.hash==hash



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


由于hashcode可以是2^32个值中的一个,因此hashmap很少有这么多的bucket(仅表就需要16GB的内存)。因此,可以在映射的同一个bucket中使用不同哈希值的对象(AFAIK这是
hachCode%numberofbucket
的简单模运算)


请注意,代码不直接使用
key.hashCode()
,而是使用
hash(key.hashCode())

此检查是一种考虑冲突的优化。
您可以有两个元素具有相同的哈希键(由于冲突),因此映射到同一个bucket。相同的键不同的实际元素。

所以如果
e.hash!=hash
您不需要检查相等性(这可能是一个昂贵的操作)

答案令人惊讶地是肯定的。我将Sysout放入put()的代码中以观察其行为
public V put(K key, V value) {
    if (table == EMPTY_TABLE) {
        System.out.println("Put: Table empty. Inflating table to threshold:" + threshold);
        inflateTable(threshold);
    }
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key);
    System.out.println("Put: Key not null:" + hash);
    int i = indexFor(hash, table.length);
    System.out.println("Put: Obtained index:" + i);
    for (Entry<K, V> e = table[i]; e != null; e = e.next) {
        System.out.println("Put: Iteraing over table[" + i + "] elements");
        Object k;
        System.out.println("Put: Checking if hash & key are equal");
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }
    System.out.println("Put: Incrementing modCounter");
    modCount++;
    System.out.println("Put: Adding a new Entry[hash="
            + hash + ", key=" + key + ", value="
            + value + ", i=" + i + "]");
    addEntry(hash, key, value, i);
    return null;
}

如您所见,两个条目存储在同一个索引中。看到这种行为我非常激动。好奇地试图得到答案。

有40亿个不同的散列值,但通常较少的存储桶。因此,具有不同散列值的对象可能仍然会在同一个bucket中结束。(如果存在
N
bucket,则bucket索引通常选择为
o.hashCode()%N
)此外,比较哈希代码非常快(它们只是
int
s),而比较对象是否相等可能非常慢。如果散列码不同,对象就不可能相等,因此在这种情况下跳过对
equals()
的调用是一个胜利。实际上是
h&(length-1)
,因为长度总是2的幂,但谁在计数呢?=)
MyHashMap p = new MyHashMap<>();
p.put(0, "Z");
p.put(1, "A");
p.put(17, "A");
Put: Table empty. Inflating table to threshold:16
Inflate: RoundUpPowerOf2 of size=16
Inflate: Setting Min of [capacity * loadFactor, MAXIMUM_CAPACITY + 1] as threshold
Inflate: Given values[capacity=16, loadfactor=0.75, MAXIMUM_CAPACITY=1073741824
Creating array of Entry[] with size:16
Put: Key not null:0
IndexFor: calculating index for [given hash=0, length=16]
Put: Obtained index:0
Put: Incrementing modCounter
Put: Adding a new Entry[hash=0, key=0, value=Z, i=0]
Put: Key not null:1
IndexFor: calculating index for [given hash=1, length=16]
Put: Obtained index:1
Put: Incrementing modCounter
Put: Adding a new Entry[hash=1, key=1, value=A, i=1]
Put: Key not null:16
IndexFor: calculating index for [given hash=16, length=16]
Put: Obtained index:0
Put: Iteraing over table[0] elements
Put: Incrementing modCounter
Put: Adding a new Entry[hash=16, key=17, value=A, i=0]