具有 Null Key 和 Null Value 的 HashMap

问题描述 投票:0回答:6

考虑以下代码:

import java.util.*;

class Employee {
    
    String name;
    
    public Employee(String nm) {
        this.name=nm;
    }
}

public class HashMapKeyNullValue {
    
    Employee e1;
    
    public void display(){

        Employee e2=null;
        Map map=new HashMap();

        map.put(e2, "25");
        System.out.println("Getting the Value When e2 is set as KEY");
        System.out.println("e2 : "+map.get(e2));
        System.out.println("e1 : "+map.get(e1));
        System.out.println("null : "+map.get(null));

        map.put(e1, "");
        System.out.println("Getting the Value when e1 is set as KEY");
        System.out.println("e2 : "+map.get(e2));
        System.out.println("e1 : "+map.get(e1));
        System.out.println("null : "+map.get(null));

        map.put(null, null);   // null as key and null as value
        System.out.println("Getting the Value when setting null as KEY and null as value");
        System.out.println("e2 : "+map.get(e2));
        System.out.println("e1 : "+map.get(e1));
        System.out.println("null : "+map.get(null));

        map.put(null, "30");
        System.out.println("Getting the Value when setting only null as KEY");
        System.out.println("e2 : "+map.get(e2));
        System.out.println("e1 : "+map.get(e1));
        System.out.println("null : "+map.get(null));
    }
    
    public static void main(String[] args) {
        
        new HashMapKeyNullValue().display();
        
    }
}

程序的输出是:

Getting the Value When e2 is set as KEY
e2 : 25
e1 : 25
null : 25
Getting the Value when e1 is set as KEY
e2 : 
e1 : 
null : 
Getting the Value when setting null as KEY and null as value
e2 : null
e1 : null
null : null
Getting the Value when setting only null as KEY
e2 : 30
e1 : 30
null : 30

这里

e1, e2, and null
作为键是如何相互关联的。所有三个都分配给相同的哈希码吗?如果是,为什么?

由于这三个值看起来不同,一个值的变化会改变另一个值。这是否意味着,只有一个密钥条目被写入

HashMap
e1, e2 or null
中?因为所有的都被视为相同的密钥。

java collections null hashmap hashcode
6个回答
75
投票

null 作为 key 传递并且 null Key 作为特殊情况处理时,

HashMap 不会调用 hashcode。

放置方法

HashMap
null 键放入存储桶 0 中,并将 null 映射为传递值的键。 HashMap是通过链表数据结构来实现的。 HashMap内部使用链表数据结构。

HashMap
使用的链表数据结构(
HashMap.java
中的静态类)

static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        final int hash;
}

在 Entry 类中,K 设置为 null,并将值映射到 put 方法中传递的值。

获取方法

Hashmap
get 方法中检查 key 是否作为 null 传递。在存储桶 0 中搜索 null 键的值。

因此,一个

hashmap
对象中只能有一个空键。


8
投票

如果您传递

null
作为地图键,它将转到
0 bucket
。空键的所有值都会去那里。这就是为什么它返回相同的值,因为您提供的所有键都是
null
并且位于 HashMap 的同一个存储桶中。


4
投票

null key 的情况下,Hashmap 实现将其视为特殊情况,不会调用 hashCode 方法,而是将 Entry 对象存储到 0 存储桶位置。


2
投票

HashMap 每个键只能存储一个值。如果您想存储更多值,则必须使用 MultivalueHashMap(Google Guava 和 Apache Commons Collections 包含此类映射的实现)。

e1 和 e2 的值为 null,因为您没有为它们分配任何对象。因此,如果您使用这些变量,则该映射条目的键也是 null,这会导致您的结果。 Null 没有任何哈希码,但可以作为 HashMap 中的键(还有其他 Map 实现不允许 Null 作为键)。


1
投票

当您将 NULL 放入 HashMap 时,如果您尝试将 NULL 作为键(称为 putForNullKey()),则会进行特殊检查。这是特殊情况,工作方式不像您尝试放置一些不为空的对象,并且您可能会看到它甚至不进行哈希计算。

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

private V putForNullKey(V value) {
    for (Entry<K,V> e = table[0]; e != null; e = e.next) {
        if (e.key == null) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }
    modCount++;
    addEntry(0, null, value, 0);
    return null;
}

0
投票

HashMap 中的所有插入:

map.put(e2, "25");
map.put(e1, "");
map.put(null, null);
map.put(null, "30");

null
作为密钥,因为在您的代码中 e1e2 设置为
null
。使用相同的键只能存储一个值。在这种情况下,存储在映射中的
null
键的值会在代码中每次
put
调用后更新。

© www.soinside.com 2019 - 2024. All rights reserved.