Java - Difference between getClass() and instanceof in equals() method?

You might have seen both getClass(), and instanceof operator in Java can be used in the equals() method to verify the type of the object you are checking for equality. Do you know what the difference is between using getClass() vs instanceof operator in Java? What would be the consequence of using one over the other in the equals() method? This is one of the tricky Java interview questions, which some of you might have encountered. There is a very subtle difference between getClass() and instanceof operator, which can cause potential issues with respect to the equals() method. 

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. 

This can break the symmetry clause of the equals() method but can also be leveraged for flexibility and performance as Hibernate does by using proxies in place of actual classes. Let's see some code examples to understand this difference better.

Difference between instanceof vs getClass() in Java

Before jumping into the equals() method and how they break the symmetry clause let's verify the behavior getClass() and instanceof operator in Java. Consider the below code, what do you think it will return, true or false?

boolean result = (loader.getClass() == Thread.class); // true

result = (loader.getClass() == Runnable.class); 
// false because we are testing against Runnable

result = loader instanceof Thread; 
// true because the loader is an object of Thread class

result = loader instanceof Runnable; 
// true because the loader is an instance of Thread 
// and it implements Runnable

So, you can see that getClass() put a restriction that objects are only equal to other objects of the same class, the same runtime type, but instanceof operator returns true for subclass as well.

If you use the getClass() in the equals() method then it will only return true if the other object is also of the same class or same runtime type, it will return false even if its object of subclass and follow the Liskov substitution principle. 

Due to this restriction, many Java developers including the great Joshua Bloch have recommended using the instanceof operator in equals() method.

Java - Difference between getClass() and instanceof in equals() method?

The instanceof operator lets you implement equality between super class and sub class. This is very important from the Collections framework perspective which uses the equals() method to find values. If you use the instanceof operator in equals() method then you can retrieve values even with the object of the subclass as a key provided they have the same content, but this is not possible when you use the getClass() method.

Hibernate relies for its performance gain on this behavior of instanceof operator. If you remember, there is a restriction in place for any Entity or Persistence class in Hibernate that it cannot be final.

This is because hibernate internally creates Proxy classes by extending your Entity class and use it until you really need an attribute from the database. Since instanceof is used to verify the type of object, a Proxy can be equal to the original object.

On the other hand, using instanceof operator has one disadvantage as well. It doesn't respect the symmetry contract of equals() method. The symmetry property says that if x.equals(y) is true then y.equals(x) should also be true, but if you swap x with subclass then x instanceof y would be true but y instanceof x will be false, hence equals() method will return false. 

This is the fact you should consider when deciding whether to use getClass() or instanceof operator for overriding equals() in Java.

That's all on the difference between getClass() and instanceof in Java. Just remember that getClass() return false if you compare it with the instanceof the subclass but the instance of operator trues if the object is a subclass of the class on the right-hand side of the operator. 

The biggest disadvantage of using getClass() in the equals() method is the fact that you get two objects that appear to be equal (because they are equal on all the fields) but they are not equal because they are of different classes. 

This can cause surprising behavior hence Joshua Bloch and others recommend using the instanceof operator inside equals() method in Java.

No comments:

Post a Comment

Feel free to comment, ask questions if you have any doubt.