2

In the post What issues should be considered when overriding equals and hashCode in Java? one explains in great detail how to write proper equality method in Java using getClass to compare RUntime types of two objects we equate. I understand that the reason we do this is to make sure that if B extends A we want a.equals(b) = b.equals(a) (reflexivity).

It does provide a big limitation in my opinion. If you have a collection of objects A, inswert a few B objects as they are subclasses of A, then a.equals(b) is always false... Perhaps, at certain times, we should stick to the old instanceof operator to provide polymorphism and allow equality of subtypes? What are your thoughts?

Community
  • 1
  • 1
Bober02
  • 15,034
  • 31
  • 92
  • 178

2 Answers2

4

You need only look as far as java.util to see examples of where .equals() gets redefined to care only about interface. For example, java.util.List, where the relevant characteristics equality is defined, and the formula for calculating the hash code is explicitly documented.

So to answer your question, yes -- ignoring subtypes makes sense under certain circumstances. But I like Josh Bloch's approach to this by making an interface the aspect of equivalence.

Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
Dilum Ranatunga
  • 13,254
  • 3
  • 41
  • 52
1

It is not necessarily the case. For example, if you look at the collections in the JDK, they use a less strict definition for equality. The code below outputs "true" twice. In the end, it is a matter of contract and documentation.

equals contract in List (emphasis mine):

Compares the specified object with this list for equality. Returns true if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal. (Two elements e1 and e2 are equal if (e1==null ? e2==null : e1.equals(e2)).) In other words, two lists are defined to be equal if they contain the same elements in the same order. This definition ensures that the equals method works properly across different implementations of the List interface.

Note that it does not breach the reflexivity requirement as long as all the classes that implement List respect that contract.

public static void main(String[] args) {
    List<String> list1 = new ArrayList<String>();
    list1.add("a");

    List<String> list2 = new LinkedList<String>();
    list2.add("a");

    List<String> list3 = Arrays.asList("a");

    System.out.println("arraylist = linkedlist? " + list1.equals(list2));
    System.out.println("arraylist = Arrays.aslit? " + list1.equals(list3));
}
assylias
  • 321,522
  • 82
  • 660
  • 783