This discussion is archived
7 Replies Latest reply: Apr 18, 2013 5:32 AM by gimbal2 RSS

equals method and contains

csh Journeyer
Currently Being Moderated
Hi,

I've overridden the equals method of an object and put it into an ArrayList.

When I call list.contains("string"), I would have expected that each element of the ArrayList calls its equals method (my overriden one) and passes "string".

But instead the equals method is called on "string", which gets passed my object.

Is that a bug or is that by design?

import java.util.ArrayList;
import java.util.List;

public class TestApp {

    public static void main(String[] args) {


        List<MyObject> myList = new ArrayList<MyObject>();

        myList.add(new MyObject("test"));

        System.out.println(myList.contains("test")); // Returns false, but expected true.
    }

    private static class MyObject {

        private String s;

        private MyObject(String s) {
            this.s = s;
        }

        @Override
        public boolean equals(Object o) {
            if (o != null && o instanceof MyObject) {
                return ((MyObject) o).s.equals(s);
            }
            return false;
        }

        @Override
        public int hashCode() {
            return s.hashCode();
        }
    }
From Java API:
public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i])) // THIS SHOULD BE THE OTHER WAY ROUND.
return i;
}
return -1;
}
Edited by: csh on 16.04.2013 02:21                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
  • 1. Re: equals method and contains
    gimbal2 Guru
    Currently Being Moderated
    Check out your equals. It does not expect a String - it expects a MyObject. And rightfully so, a String object should never be equal to a MyObject object.

    So I would expect you to do this:
    System.out.println(myList.contains(new MyObject("test")));
  • 2. Re: equals method and contains
    csh Journeyer
    Currently Being Moderated
    Ok, and what about this?:
    @Override
            public boolean equals(Object o) {
                if (o != null && (o instanceof MyObject || o instanceof String)) {
                    if (o instanceof String) {
                        return s.equals(o);
                    }
                    return ((MyObject) o).s.equals(s);
                }
    
                return false;
            }
  • 3. Re: equals method and contains
    Kayaman Guru
    Currently Being Moderated
    Nope. That still allows MyObject to equal to String. That breaks the contract for the equals() method.

    If o is not instanceof MyObject, you must return false.
  • 4. Re: equals method and contains
    jtahlborn Expert
    Currently Being Moderated
    Kayaman wrote:
    Nope. That still allows MyObject to equal to String. That breaks the contract for the equals() method.

    If o is not instanceof MyObject, you must return false.
    that's not strictly true, but it generally holds. the more important rule is that equals must be commutative, i.e. if "a.equals(b)" then "b.equals(a)". in this case "String.equals(MyObject)" will never be true, so this is a bad implementation of equals.
  • 5. Re: equals method and contains
    1003353 Newbie
    Currently Being Moderated
    sometimes exists a == b, but b != a, for example:
    Map<String, String> map1 = new IdentityHashMap<String, String>();
    map1.put("1", new String("2"));
    Map<String, String> map2 = new HashMap<String, String>();
    map2.put("1", "2");
    System.out.println(map1.equals(map2));   // false
    System.out.println(map2.equals(map1));   // true
    This isn't a bug, because the comment in IdentityHashMap
    This class implements the <tt>Map</tt> interface with a hash table, using
    reference-equality in place of object-equality when comparing keys (and
    values).
  • 6. Re: equals method and contains
    jtahlborn Expert
    Currently Being Moderated
    1000350 wrote:
    sometimes exists a == b, but b != a, for example:
    i didn't say it didn't exist. that still technically violates the contract for equals. whether or not that was a good idea is up to the designers of IdentityHashMap.
  • 7. Re: equals method and contains
    gimbal2 Guru
    Currently Being Moderated
    1000350 wrote:
    sometimes exists a == b, but b != a, for example:
    Map<String, String> map1 = new IdentityHashMap<String, String>();
    map1.put("1", new String("2"));
    Map<String, String> map2 = new HashMap<String, String>();
    map2.put("1", "2");
    System.out.println(map1.equals(map2));   // false
    System.out.println(map2.equals(map1));   // true
    This isn't a bug, because the comment in IdentityHashMap
    This class implements the <tt>Map</tt> interface with a hash table, using
    reference-equality in place of object-equality when comparing keys (and
    values).
    Nice find. I wonder if another example can be found though, this seems like a rare exception to the rule where breaking the equals contract was only done because there was no other choice. I would -not- use this to justify breaking it in other classes because it is convenient.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points