1

I've seen many implementations of the java equals() method which go along the following lines:

public boolean equals(Object other){
    if (this == other) 
        return true;

    //this if code
    if (!(other intanceof MyClass))
        return false;
    //ends here

    otherMyClass = (MyClass)other;
    //check all the attribute of this and otherMyClass and return true or false
    //accordingly
}

Isn't the code in if problematic in the sense that it will return true for o1.equals(o2) (with o1 objects of MyClass and o2 objects of subclasses of MyClasss) ? Which, in most of the cases, is not the expected behavior.

Wouldn't other.getClass() != this.getClass() be a better comparison instead of the bolded if above ?

Razvan
  • 9,925
  • 6
  • 38
  • 51
  • 2
    Check out this question: http://stackoverflow.com/questions/596462/any-reason-to-prefer-getclass-over-instanceof-when-generating-equals – Chris Forrence Jan 28 '14 at 14:44

4 Answers4

3

o.getClass() != getClass()) violates Liskov substitution principle.

To quote a great man:

The Liskov substitution principle says that any important property of a type should also hold for its subtypes, so that any method written for the type should work equally well on its subtypes.

The book Effective Java has more details on this topic.

Nigel Tufnel
  • 11,146
  • 4
  • 35
  • 31
  • 2
    But equality has to be commutative (i.e `if a==b then b==a`) which might not be the case in this scenario. I think you can ignore LSP for an `equals` method... – RB. Jan 28 '14 at 14:47
  • then there should be a liskov substitution principle especially defined for java equals() – Razvan Jan 28 '14 at 14:48
  • If a type's contract defines an equivalence relation which specifically allows instances of different subtype to compare equal, then every subtype must define its equals method to test for that equivalence relation and no other. Otherwise, nothing about the LSP suggests that it must be possible to create an instance of any particular class which reports itself as equivalent to any other object, whether that object be of that same class or a different one. An object's `getClass()` 'value' is no less legitimate a basis of comparison than would be anything else. – supercat Jan 30 '14 at 00:01
0

if (!(other intanceof MyClass)) return false will return false if they are instances of different classes.

I can't follow your logic about returning true, since it can't return true. It can evaluate to true though, in which case the next statements are executed.

Xabster
  • 3,710
  • 15
  • 21
0

I think that the best answer is referenced in comment by @ChrisForrence (+1): Any reason to prefer getClass() over instanceof when generating .equals()?

I wanted to pay your attention of fact that using instanceof makes equals() implementation not symmetric: if A is a base class and B extends A without defining any other fields or methods it can be that a.equals(b) == true but b.equals(a) == false where a is instance of A and b is instance of B.

Community
  • 1
  • 1
AlexR
  • 114,158
  • 16
  • 130
  • 208
  • I agree! So getClass() is the way to go (after you clearly define the concept of object equivalence in the case of your system). – Razvan Jan 28 '14 at 14:56
  • @Razvan, sounds like `getClass()` is better. And this is despite of the fact that I have been using `instanceof` into `equals()` for 15 years... But from other case be careful. This technique can cause problems when some of your classes are wrapped by proxies widely used by frameworks. – AlexR Jan 28 '14 at 15:33
0

I actually had this question in an interview a year ago. My implementation was with instanceof too. Just two arguments pop into my head that my interviewer mentioned towards using getClass() == other.getClass():

  • you probably never need a subclass instance in any practical situation to be equal to a parent object; the most common use for the equals method is for collections (sets more specifically); I never encountered this in practice, but if anyone here did, feel free to add as a comment any non-pure theoretical situation where this still applies (honestly, I'm curious if there is such a case)
  • keep in mind the properties of the equals contract (JavaDoc for Object):
    • reflexive
    • symmetric (*)
    • transitive
    • consistent
    • x.equals(null) returns false for any object x
      • this was already pointed out in other answers: the symmetry property can be problematic with instanceof (again, in practice, I rarely used sets containing elements of different types, but whenever I had different types, I knew from the start that the objects were in fact different)
Catalin Pol
  • 261
  • 1
  • 3