Coming to the point, the key difference between them is that getClass() only returns true if the object is actually an instance of the specified class but an instanceof operator can return true even if the object is a subclass of a specified class or interface in Java.
getClass() method returns the runtime class of an object. That Class object is the object that is locked by static synchronized methods of the represented class.
Java String equals() Method The equals() method compares two strings, and returns true if the strings are equal, and false if not. Tip: Use the compareTo() method to compare two strings lexicographically.
Josh Bloch favors your approach:
The reason that I favor the
instanceof
approach is that when you use thegetClass
approach, you have the restriction that objects are only equal to other objects of the same class, the same run time type. If you extend a class and add a couple of innocuous methods to it, then check to see whether some object of the subclass is equal to an object of the super class, even if the objects are equal in all important aspects, you will get the surprising answer that they aren't equal. In fact, this violates a strict interpretation of the Liskov substitution principle, and can lead to very surprising behavior. In Java, it's particularly important because most of the collections (HashTable
, etc.) are based on the equals method. If you put a member of the super class in a hash table as the key and then look it up using a subclass instance, you won't find it, because they are not equal.
See also this SO answer.
Effective Java chapter 3 also covers this.
If you use instanceof
, making your equals
implementation final
will preserve the symmetry contract of the method: x.equals(y) == y.equals(x)
. If final
seems restrictive, carefully examine your notion of object equivalence to make sure that your overriding implementations fully maintain the contract established by the Object
class.
Angelika Langers Secrets of equals gets into that with a long and detailed discussion for a few common and well-known examples, including by Josh Bloch and Barbara Liskov, discovering a couple of problems in most of them. She also gets into the instanceof
vs getClass
. Some quote from it
Conclusions
Having dissected the four arbitrarily chosen examples of implementations of equals() , what do we conclude?
First of all: there are two substantially different ways of performing the check for type match in an implementation of equals() . A class can allow mixed-type comparison between super- and subclass objects by means of the instanceof operator, or a class can treat objects of different type as non-equal by means of the getClass() test. The examples above illustrated nicely that implementations of equals() using getClass() are generally more robust than those implementations using instanceof .
The instanceof test is correct only for final classes or if at least method equals() is final in a superclass. The latter essentially implies that no subclass must extend the superclass's state, but can only add functionality or fields that are irrelevant for the object's state and behavior, such as transient or static fields.
Implementations using the getClass() test on the other hand always comply to the equals() contract; they are correct and robust. They are, however, semantically very different from implementations that use the instanceof test. Implementations using getClass() do not allow comparison of sub- with superclass objects, not even when the subclass does not add any fields and would not even want to override equals() . Such a "trivial" class extension would for instance be the addition of a debug-print method in a subclass defined for exactly this "trivial" purpose. If the superclass prohibits mixed-type comparison via the getClass() check, then the trivial extension would not be comparable to its superclass. Whether or not this is a problem fully depends on the semantics of the class and the purpose of the extension.
The reason to use getClass
is to ensure the symmetric property of the equals
contract. From equals' JavaDocs:
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
By using instanceof, it's possible to not be symmetric. Consider the example:
Dog extends Animal.
Animal's equals
does an instanceof
check of Animal.
Dog's equals
does an instanceof
check of Dog.
Give Animal a and Dog d (with other fields the same):
a.equals(d) --> true
d.equals(a) --> false
This violates the symmetric property.
To strictly follow equal's contract, symmetry must be ensured, and thus the class needs to be the same.
This is something of a religious debate. Both approaches have their problems.
Bloch has another relevant piece of advice in Effective Java Second Edition:
Correct me if I am wrong, but getClass() will be useful when you want to make sure your instance is NOT a subclass of the class you are comparing with. If you use instanceof in that situation you can NOT know that because:
class A { }
class B extends A { }
Object oA = new A();
Object oB = new B();
oA instanceof A => true
oA instanceof B => false
oB instanceof A => true // <================ HERE
oB instanceof B => true
oA.getClass().equals(A.class) => true
oA.getClass().equals(B.class) => false
oB.getClass().equals(A.class) => false // <===============HERE
oB.getClass().equals(B.class) => true
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With