具有空键和空值的HashMap

时间:2014-09-19 11:19:03

标签: java collections null hashmap hashcode

请考虑以下代码:

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 {{1}},因为所有条目都被视为相同的密钥。

5 个答案:

答案 0 :(得分:33)

null 作为键传递时,

HashMap 不会调用哈希码,并且将null键作为特殊情况处理。

放置方法

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 获取方法时,检查密钥是否作为 null 传递。在存储桶 0 中搜索 null 键的值。

因此,一个 hashmap 对象中只能有一个空键

答案 1 :(得分:6)

如果您将null作为地图密钥传递,则会转到0 bucket。 null键的所有值都将在那里。这就是为什么它返回相同的值,因为你提供的所有键都是null并且在你的HashMap的同一个桶中。

答案 2 :(得分:2)

包含 null 键,Hashmap实现将其视为特例,并且不调用hashCode方法,而是将Entry对象存储到0桶位置。

答案 3 :(得分:1)

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

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

答案 4 :(得分: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;
}