在 Java 的 ArrayList 中使用 contains 的最佳方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/986924/
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-11 21:54:57  来源:igfitidea点击:

Best way to use contains in an ArrayList in Java?

javaarraylistcontains

提问by

I have an ArrayList in Java which is made up of a type containing two strings and an integer. I can successfully test if one element of this ArrayList equals another but I find that the contains method fails. I believe this is due to the fact that my type is not primitive.

我在 Java 中有一个 ArrayList,它由包含两个字符串和一个整数的类型组成。我可以成功测试此 ArrayList 的一个元素是否等于另一个元素,但我发现 contains 方法失败。我相信这是因为我的类型不是原始类型。

Now I see two alternatives to this and I wonder which is the best option:

现在我看到了两个替代方案,我想知道哪个是最好的选择:

  1. To implement my own contains method by iterating through the ArrayList and testing equality of each element against the one I'm looking for and then breaking the loop.

  2. Or to use a HashMap of my type as key with an integer as value instead of the ArrayList. Here I can use method containsKey to check if an element already exists in the HashMap.

  1. 通过遍历 ArrayList 并测试每个元素与我正在寻找的元素的相等性,然后打破循环来实现我自己的 contains 方法。

  2. 或者使用我的类型的 HashMap 作为键,使用整数作为值而不是 ArrayList。在这里,我可以使用方法 containsKey 来检查元素是否已存在于 HashMap 中。

The only caveat with approach to #2 is that the value is largely redundant in my case.

对#2 方法的唯一警告是,在我的情况下,该值在很大程度上是多余的。

回答by Michael Myers

Most likely, you have simply forgotten to override equals()and hashCode()in your type. equals()is what contains()checks for.

最有可能的是,您只是忘记了覆盖equals()hashCode()使用您的类型。equals()是什么contains()检查。

From the Javadoc:

Javadoc

Returns trueif this list contains the specified element. More formally, returns trueif and only if this list contains at least one element esuch that (o==null ? e==null : o.equals(e)).

返回true此列表是否包含指定的元素。更正式地说,true当且仅当此列表包含至少一个元素e使得(o==null ? e==null : o.equals(e)).

Since the default implementation of equalstests for reference equality, it's not suitable for custom data types like this one.

由于equals引用相等性测试的默认实现,它不适合像这样的自定义数据类型。

(And if you didn't override equalsand hashCode, using your types as keys in a HashMapwould be equally futile.)

(如果您没有覆盖equalsand hashCode,将您的类型用作 a 中的键HashMap同样是徒劳的。)



Edit:Note that to override, you must provide the exactsignature.

编辑:请注意,要覆盖,您必须提供准确的签名。

class MyDataType {
    public boolean equals(MyDataType other) { // WRONG!
        ...
    }
    public boolean equals(Object other) { // Right!
        ...
    }
}

This is a very strong argument for using the @Overrideannotation; the first example would have failed at compile time if annotated with @Override.

这是使用@Override注释的一个非常有力的论据;如果用@Override.

回答by amarillion

Did you override the equals method? This is required to make contains work correctly.

您是否覆盖了 equals 方法?这是使包含正确工作所必需的。

回答by Rickster

maybe use the Integer class instead? then you can do object comparison

也许改用 Integer 类?然后你可以做对象比较

回答by Jon Skeet

My guess is that you've only written a "strongly typed" equals method instead of overriding equals(Object). In other words, if you've got:

我的猜测是您只编写了一个“强类型”的 equals 方法,而不是覆盖 equals(Object)。换句话说,如果你有:

public boolean equals(Foo f)

you need

你需要

public boolean equals(Object o)

as well to override Object.equals.

以及覆盖 Object.equals。

That would fit with "equals works but contains doesn't because your tests probably call the strongly-typed equals, but ArrayList doesn't.

这将符合“等于有效但包含无效,因为您的测试可能调用强类型等于,但 ArrayList 没有。

回答by James

Remember that if you don't override the equals() method, then two objects of your type are only equal if they are the same instanceof that object. The ArrayList class uses this method to check that it contains the given object. Also, you need to match the signature exactly, which means that it must take an Object as a parameter and not a Foo.

请记住,如果您不覆盖 equals() 方法,那么您的类型的两个对象仅在它们是该对象的同一实例时才相等。ArrayList 类使用此方法来检查它是否包含给定的对象。此外,您需要完全匹配签名,这意味着它必须将对象作为参数而不是 Foo。

Also, the Object contract stipulates that you must override hashCode() whenever you override equals(). If you don't do this, then a HashMap or HashSet won't identify your two objects as being equal, even if the ArrayList does (HashMap checks for identical hashes and then calls equals() on them to check for actual equality). Thus, if ArrayList says that two items aren't equal, then there is no way that HashMap would either. This means that your second solution does not work.

此外,对象契约规定,无论何时覆盖 equals(),都必须覆盖 hashCode()。如果您不这样做,那么 HashMap 或 HashSet 将不会将您的两个对象标识为相等,即使 ArrayList 确实如此(HashMap 检查相同的散列,然后对它们调用 equals() 以检查实际相等)。因此,如果 ArrayList 说两个项目不相等,那么 HashMap 也不可能这样做。这意味着您的第二个解决方案不起作用。

My recommendation is to check that you actually override equals() and hashCode() properly and that their signatures match the ones in the Object class.

我的建议是检查您实际上是否正确覆盖了 equals() 和 hashCode() 并且它们的签名是否与 Object 类中的签名相匹配。