【问题标题】:Why integer key do not work in HashMap?为什么整数键在 HashMap 中不起作用?
【发布时间】:2013-10-22 07:54:34
【问题描述】:

请参考以下代码:

public static void main (String[] args) {
    Map<Number, String> map = new HashMap<Number, String>();
    map.put(1L, "test");
    System.out.println(map.get(1));
}

为什么 HashMap.get 返回 null? O_o hashCode函数返回1的任何对象都必须返回值,不是吗?

更新

问题是 Map 接口接收 Object,而不是参数化类型。所以我原以为任何对象都可以是key,但是HashMap实现用equals检查类型,这让我很吃惊。

自动装箱不是问题。我知道,那个 1 变成了 Integer,而 1L 变成了 Long。但它们有相同的哈希码。所以我认为任何实现 Map#get 都应该为具有 same 哈希码的任何对象返回值。

【问题讨论】:

  • 试试System.out.println(map.get(1L));
  • 你说得对,整数 1 和长 1L 具有相同的哈希码,并且将存储在地图内的同一个桶中。但随后 .equals 完成并返回 false。

标签: java hashmap hashcode


【解决方案1】:

您输入 1L (Long) 的密钥并获得 1 (Integer) 的密钥。

它们不是一回事,所以要小心。

要么从 put 中删除 L,要么将 L 添加到 get。或者更好的是,不要将它们写成原语并依赖自动装箱。

【讨论】:

  • 或者不使用 HashMap 而是使用 HashMap
  • @TwoThe 确实,我都没注意。
【解决方案2】:

这是因为您在检索值时没有传递 Long 类型的键,而是一个整数。这些被自动装箱为不同的对象,因此不代表相同的键。

【讨论】:

    【解决方案3】:

    整数和长整数不一样。

    Integer#equals

    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }
    

    Long#equals

    public boolean equals(Object obj) {
        if (obj instanceof Long) {
            return value == ((Long)obj).longValue();
        }
        return false;
    }
    

    【讨论】:

      【解决方案4】:

      put 和 getting 之间的类型不匹配。

      这里发生的是 AutoBoxing,Java 将自动执行原语到其 Object 等效项之间的转换,反之亦然,而不是通过 new(),所以变成 Integer,另一个是 Long

      尝试以下方法:

      public static void main (String[] args) {
              Map<Number, String> map = new HashMap<Number, String>();
              map.put(1L, "test");
              System.out.println(map.get(1L));
          }
      

      或者

      public static void main (String[] args) {
              Map<Number, String> map = new HashMap<Number, String>();
              map.put(1, "test");
              System.out.println(map.get(1));
          }
      

      虽然两者都有相同的value(1) 但对象不同,但它们不是equal

      i.e. Integer(1) != Long(1).
      

      这就是这里的问题,这是通过使用自动装箱发生的。

      一个简单的例子

              Long l = new Long(1);
              Integer i = new Integer(1);
              System.out.println(i.equals(l)); //false -->Hashmap get() failed here
              System.out.println(i.intValue() ==l.intValue());//true
      

      【讨论】:

        【解决方案5】:

        我发现了问题,请参阅 java.util.HashMap#get 源代码,它包含:

        public V get(Object key) {
                if (key == null)
                    return getForNullKey();
                int hash = hash(key.hashCode());
                for (Entry<K,V> e = table[indexFor(hash, table.length)];
                     e != null;
                     e = e.next) {
                    Object k;
                    if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                        return e.value;
                }
                return null;
            }
        

        所以它在返回值之前检查键是否等于。

        【讨论】:

        • java.util.HashMap#get有什么问题?
        • 其实你的问题不在于get 这意味着为什么equals会失败?那是因为Auto boxing :)
        猜你喜欢
        • 2016-06-04
        • 2014-03-02
        • 1970-01-01
        • 2019-02-14
        • 2012-12-07
        • 1970-01-01
        • 2017-12-20
        • 1970-01-01
        • 2014-11-17
        相关资源
        最近更新 更多