带有 Int 数组的 Java HashMap

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2627889/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 10:04:10  来源:igfitidea点击:

Java HashMap with Int Array

javaarrayshashmap

提问by Sunil

I am using this code to check that array is present in the 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})));
    }
}

But this prints False. How can I check that array is present in the HashMap?

但这打印False. 如何检查数组是否存在于HashMap?

采纳答案by polygenelubricants

The problem is because the two int[]aren't equal.

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

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

Mapand other Java Collections Framework classes defines its interface in terms of equals. From Map API:

Map和其他 Java Collections Framework 类以equals. 来自Map API

Many methods in Collections Framework interfaces are defined in terms of the equalsmethod. For example, the specification for the containsKey(Object key)method says: "returns trueif and only if this map contains a mapping for a key ksuch that (key==null ? k==null : key.equals(k))."

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

Note that they don't have to be the same object; they just have to be equals. Arrays in Java extends from Object, whose default implementation of equalsreturns true only on object identity; hence why it prints falsein above snippet.

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



You can solve your problem in one of many ways:

您可以通过以下多种方式之一解决您的问题:

  • Define your own wrapper class for arrays whose equalsuses java.util.Arraysequals/deepEqualsmethod.
    • And don't forget that when you @Override equals(Object), you must also @Override hashCode
  • Use something like List<Integer>that doesdefine equalsin terms of the values they contain
  • Or, if you canwork with reference equality for equals, you canjust stick with what you have. Just as you shouldn't expect the above snippet to ever print true, you shouldn't ever expect to be able to find your arrays by its values alone; you must hang-on to and use the original references every time.
  • equals使用方法的数组定义自己的包装类。 java.util.Arraysequals/deepEquals
    • 并且不要忘记,当你@Override equals(Object),你也必须@Override hashCode
  • 使用类似List<Integer>的是没有定义equals在它们所包含的价值观方面
  • 或者,如果您可以使用 for 的引用相等equals,则可以坚持使用您拥有的东西。正如您不应该期望上面的代码片段永远打印一样true,您也不应该期望能够仅通过数组的值找到数组;您必须每次都坚持并使用原始参考资料。


See also:

也可以看看:

API

应用程序接口

  • Object.equalsand Object.hashCode
    • It's essential for a Java programmer to be aware of these contracts and how to make them work with/for the rest of the system
  • Object.equalsObject.hashCode
    • Java 程序员必须了解这些契约以及如何使它们与系统的其余部分一起工作/为系统的其余部分工作

回答by Sunil

I think the problem is your array is doing an '==' comparison, i.e. it's checking the reference. When you do containsKey(new int[] { ... }), it's creating a new object and thus the reference is not the same.

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

If you change the array type to something like ArrayList<Integer>that should work, however I would tend to avoid using Lists as map keys as this is not going to be very efficient.

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

回答by Yuval Adam

You are comparing two different references. Something like this will work:

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

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));
    }
}

Since ais the same reference, you will receive trueas expected. If your application has no option of passing references to do the comparison, I would make a new object type which contains the int[]and override the equals()method (don't forget to override hashCode()at the same time), so that will reflect in the containsKey()call.

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

回答by djna

You've got two different objects that happen to contain the same values, because you've called new twice.

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

One approach you might use is to create a "holder" class of your own, and define that class's equals and hash methods.

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

回答by Justin Ardini

Are you sure you don't want to map Stringsto arrays instead of the other way around?

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

Anyway, to answer your question, the problem is you are creating a newarray when you call containsKey(). This returns false between you you have two separately newed arrays that happen to have the same elements and dimension. See Yuval's answer to see the correct way of checking if an array is contained as a key.

无论如何,要回答您的问题,问题是您new在调用containsKey(). 这在您有两个单独的newed 数组之间返回 false,这些数组恰好具有相同的元素和维度。请参阅 Yuval 的回答以查看检查数组是否包含为键的正确方法。

An alternative, more advanced, approach is to create your own class that wraps an array and overwrites hashCode()so that two arrays with the same dimension and elements will have equal hash codes.

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

回答by Michael Mrozek

The hashCode()implementation for arrays is derived from Object.hashCode(), so it depends on the memory location of the array. Since the two arrays are instantiated separately, they have different memory locations and thus different hashcodes. If you made one array it would work:

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

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

回答by Eyal Schneider

I would use a different approach. As mentioned before, the problem is with arrays equality, which is based on reference equality and makes your map useless for your needs. Another potential problem, assuming that you use ArrayList instead, is the problem of consistency: if you change a list after is has been added to the map, you will have a hashmap corruption since the position of the list will not reflect its hashcode anymore.

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

In order to solve these two problems, I would use some kind of immutable list. You may want to make an immutable wrapper on int array for example, and implement equals() and hashCode() yourself.

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