【问题标题】:HashMap with Null Key and Null Value具有空键和空值的 HashMap
【发布时间】:2014-11-13 23:28:51
【问题描述】:

考虑以下代码:

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 作为键是如何相互关联的。这三个是否都分配给相同的哈希码?如果是,为什么?

由于所有三个看起来都不同,因此一个值的变化会改变另一个值。这是否意味着只有一个 key 条目被写入 HashMape1, e2, or null,因为它们都被视为同一个 key。

【问题讨论】:

  • e1 和 e2 的值为空。 Java 是按值传递的,当该变量用作调用参数时,它将仅传递该变量的值。也就是变量在函数内部永远不会被重新赋值,函数中的参数名与任何变量都没有关系。
  • HashMap having null as key 的可能重复项

标签: java collections null hashmap hashcode


【解决方案1】:

HashMapnull 作为 key 传递并且 null Key 作为特殊情况处理时不会调用 hashcode。

放置方法

HashMapnull 键放入桶 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 传递。桶 0null 键的搜索值。

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

【讨论】:

  • 仅供参考,答案是完全正确的,但是自 java 1.8 以来,HashMap 的实现略有变化。平衡树可以代替链表用作“桶”
【解决方案2】:

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

【讨论】:

  • 如果我插入两个以 NULL 为键的值,v1 和 v2。同时获取我会得到哪一个????总是最后一个?
  • @dineshkandpal 是的,总是最后一个(v2)
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      当您将 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;
      }
      

      【讨论】:

        猜你喜欢
        • 2021-01-25
        • 1970-01-01
        • 1970-01-01
        • 2020-05-11
        • 1970-01-01
        • 2016-06-06
        • 2016-12-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多