-1

I have two ArrayLists that are equal under the equals() method, but they have different hashcodes. What is going on here?

According to the Java List API: "list1.equals(list2) implies that list1.hashCode()==list2.hashCode() for any two lists, list1 and list2, as required by the general contract of Object.hashCode()."

Here is the code:

    List<nut> l1= new ArrayList<>(Arrays.asList(new nut((short) 4, (short) 2),
        new nut((short) 5, (short) 0), new nut((short) 1, (short) 3)));
    List<nut> l2= new ArrayList<>(Arrays.asList(new nut((short) 4, (short) 2),
        new nut((short) 5, (short) 0), new nut((short) 1, (short) 3)));
    System.out.println(l1.equals(l2));
    System.out.println(l1.hashCode());
    System.out.println(l2.hashCode());

output: true -2130368428 1856372392

Dave
  • 1
  • Please [edit] your question to include the source code of the `nut` class. Most likely you are not overriding the `hashcode()` method as required. – Progman Mar 14 '21 at 20:43
  • 2
    How are `equals` and `hashCode` and the constructor defined for your `nut` class? I would assume the problem to lie there. – FrankPl Mar 14 '21 at 20:44
  • 1
    `ArrayList` implements both `equals()` and `hashCode()` as an aggregation of the corresponding methods of the elements in the list, so if they are wrong, it's because the elements are doing them wrong. The `hashCode()` implementation of class `nut` is violating the [general contract](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-), specifically bullet 2: *"If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result"*. – Andreas Mar 14 '21 at 20:51
  • Ah, I see. I need to override the hashcode function in the nut class. Thank you all! – Dave Mar 14 '21 at 21:10

1 Answers1

2

Check implementation of equals() and hashcode() of AbstractList (ArrayList is extending that class)

public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof List))
            return false;

        ListIterator<E> e1 = listIterator();
        ListIterator<?> e2 = ((List<?>) o).listIterator();
        while (e1.hasNext() && e2.hasNext()) {
            E o1 = e1.next();
            Object o2 = e2.next();
            if (!(o1==null ? o2==null : o1.equals(o2)))
                return false;
        }
        return !(e1.hasNext() || e2.hasNext());
}

public int hashCode() {
        int hashCode = 1;
        for (E e : this)
            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
        return hashCode;
}

It's iterating through objects in lists and calling equals()/hashcode() on them. Therefore responsibility of handling this lays on you as you provided your nut class in generic type.

The answer is: you messed up contract between hashcode() and equals() in you nut class.

Progman
  • 16,827
  • 6
  • 33
  • 48
Krzysztof K
  • 736
  • 4
  • 19