Best way to use contains in an ArrayList in Java?

2019-02-16 23:09发布

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.

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.

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

5条回答
beautiful°
2楼-- · 2019-02-16 23:11

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

查看更多
劳资没心,怎么记你
3楼-- · 2019-02-16 23:13

Remember that if you don't override the equals() method, then two objects of your type are only equal if they are the same instance of 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.

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.

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

查看更多
仙女界的扛把子
4楼-- · 2019-02-16 23:18

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:

public boolean equals(Foo f)

you need

public boolean equals(Object o)

as well to override 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.

查看更多
劫难
5楼-- · 2019-02-16 23:19

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

From the Javadoc:

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

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

(And if you didn't override equals and hashCode, using your types as keys in a HashMap would be equally futile.)


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

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

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

查看更多
老娘就宠你
6楼-- · 2019-02-16 23:28

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

查看更多
登录 后发表回答