带有Int数组的Java HashMap

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

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

但这打印错误。 如何检查HashMap中是否存在该数组。 提前致谢。

问题是因为两个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)方法的规范说:“当且仅当此映射包含键k的映射时才返回true (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这样的东西, 根据它们包含的值来定义equals
  • 或者,如果你可以使用equals引用equals ,你可以坚持使用你拥有的东西。 就像你不应该期望上面的代码段打印出来一样true ,你不应该期望能够仅通过其值来找到你的数组; 你必须每次都坚持使用原始参考文献。

也可以看看:

  • 在Java中覆盖equals和hashCode
  • 如何确保hashCode()与equals()一致?
  • 了解HashMap中equals和hashCode的工作原理

API

  • Object.equalsObject.hashCode
    • 对于Java程序员来说,了解这些合同以及如何使它们与系统的其余部分一起工作至关重要

您正在比较两个差异参考 – 请注意new的两次使用。 这样的东西会起作用:

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

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

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

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

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

如果您将数组类型更改为类似ArrayList类型,但是我倾向于避免使用Lists作为映射键,因为这不会非常有效。

数组的hashCode()实现派生自Object.hashCode() ,因此它取决于数组的内存位置。 由于两个数组是分开实例化的,因此它们具有不同的存储器位置,因此具有不同的哈希码。 如果您创建了一个数组,它将起作用:

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

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

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

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

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

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