带有Int数组的Java HashMap

时间:2010-04-13 08:03:04

标签: java arrays hashmap

我正在使用此代码检查HashMap中是否存在该数组。

public class Test {
    public static void main(String[]arg)
    {
     HashMap<int[],String> map= new HashMap<int[],String>();
     map.put(new int[]{1,2}, "sun");
     System.out.println(map.containsKey((new int[]{1,2})));
    }
}

但这会打印出来。 如何检查HashMap中是否存在该数组。 提前谢谢。

7 个答案:

答案 0 :(得分:29)

问题是因为两个int[]不相等。

System.out.println(
    (new int[] { 1, 2 }).equals(new int[] { 1, 2 })
); // prints "false"

Map和其他Java Collections Framework类根据equals定义其接口。来自Map API

  

Collections Framework接口中的许多方法都是根据equals方法定义的。例如,containsKey(Object key)方法的规范说:“返回true当且仅当此地图包含关键k的映射,使(key==null ? k==null : key.equals(k))。”

请注意,它们不必是同一个对象;他们只需要equals。 Java中的数组从Object扩展而来,equals的默认实现仅在对象标识上返回true;因此,为什么它会在上面的代码段中打印false


您可以通过多种方式解决问题:

  • equals使用java.util.Arrays equals/deepEquals方法的数组定义自己的包装类。
    • 不要忘记,当您@Override equals(Object)时,您还必须@Override hashCode
  • 使用 定义List<Integer> equals之类的内容
  • 或者,如果您可以使用equals的引用相等性,那么可以坚持使用您拥有的内容。就像你不应该期望上面的代码段打印true一样,你不应该期望能够仅通过其值来找到你的数组;你必须每次都坚持使用原始参考文献。

另见:

API

  • Object.equalsObject.hashCode
    • 让Java程序员了解这些合同以及如何使它们与系统的其余部分一起使用是至关重要的

答案 1 :(得分:8)

您正在比较两个差异参考 - 请注意new的双重用法。 这样的事情会起作用:

public class Test {
    public static void main(String[] arg)
    {
     HashMap<int[],String> map= new HashMap<int[],String>();
     int[] a = new int[]{1,2};
     map.put(a, "sun");
     System.out.println(map.containsKey(a));
    }
}

由于a是相同的引用,您将按预期收到true。如果您的应用程序没有选择传递引用来进行比较,我会创建一个包含int[]的新对象类型并覆盖equals()方法(不要忘记覆盖hashCode()同时),这将反映在containsKey()电话中。

答案 2 :(得分:4)

我会使用不同的方法。如前所述,问题在于数组相等性,它基于引用相等性而使您的地图无法满足您的需求。 另一个潜在的问题,假设您使用ArrayList,是一致性的问题:如果在将地图添加到地图后更改列表,则会出现哈希图损坏,因为列表的位置将不再反映其哈希码。

为了解决这两个问题,我会使用某种不可变列表。例如,你可能想在int数组上创建一个不可变的包装器,并自己实现equals()和hashCode()。

答案 3 :(得分:2)

我认为问题是你的数组正在进行'=​​='比较,即它正在检查引用。当你执行containsKey(new int [] {...})时,它正在创建一个新对象,因此引用不一样。

如果您将数组类型更改为ArrayList<Integer>应该有效的类型,但我倾向于避免使用Lists作为地图键,因为这不会非常有效。

答案 4 :(得分:2)

数组的hashCode()实现派生自Object.hashCode(),因此它取决于数组的内存位置。由于两个数组分别实例化,因此它们具有不同的存储器位置,因此具有不同的哈希码。如果你制作了一个数组,那就可以了:

int[] arr = {1, 2};
map.put(arr, "sun");
System.out.println(map.containsKey(arr));

答案 5 :(得分:1)

你有两个碰巧包含相同值的不同对象,因为你已经调用了两次。

您可能使用的一种方法是创建自己的“holder”类,并定义该类的equals和hash方法。

答案 6 :(得分:1)

您确定不想将Strings映射到数组而不是相反吗?

无论如何,要回答您的问题,问题是您在拨打new时正在创建containsKey()数组。在您有两个具有相同元素和维度的单独new ed数组之间返回false。请参阅Yuval的答案,以查看检查数组是否作为键包含的正确方法。

另一种更高级的方法是创建自己的包装数组并覆盖hashCode()的类,以便具有相同维度和元素的两个数组具有相同的哈希码。