繁体   English   中英

带有 Int 数组的 Java HashMap

[英]Java HashMap with Int Array

我正在使用此代码来检查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})));
    }
}

但这会打印False 如何检查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)方法表示:“返回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引用equals ,则可以坚持使用您拥有的内容。 正如您不应该期望上面的代码片段打印true ,您也不应该期望能够仅通过数组的值找到数组; 您必须每次都坚持并使用原始参考资料。

也可以看看:

应用程序接口

  • Object.equalsObject.hashCode
    • Java 程序员必须了解这些契约以及如何使它们与系统的其余部分一起工作/为系统的其余部分工作

您正在比较两个不同的参考。 像这样的事情会起作用:

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()调用中。

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

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

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

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

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

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM