The Artima Developer Community
Sponsored Link

Josh Bloch on Design
A Conversation with Effective Java Author, Josh Bloch
by Bill Venners
First Published in JavaWorld, January 4, 2002

<<  Page 17 of 19  >>

Advertisement

instanceof versus getClass in equals Methods

Bill Venners: In an equals method, should I use instanceof or Class comparison to determine if the passed object is the "same" type as this one?

Josh Bloch: The book has an item about the equals method in the 'Methods Common to all Objects' chapter. All the equals methods discussed in that chapter use instanceof rather than getClass. I knew that some people use getClass, but I thought the technique was not widely used. The essay was long and complex already, so I thought I wouldn't confuse the issue by discussing another technique which I thought was inferior. But it turned out to be a mistake. It seems that getClass-based equals methods are fairly widely used and discussed in other books. This turns out to be perhaps the most controversial item in the book. I got a lot of email on the subject.

The reason that I favor the instanceof approach is that when you use the getClass 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.

Because of these problems, I didn't even bother discussing the getClass approach. But it turns out that because it does let you add aspects while preserving the equals contract, some people favor it. So I just want to get the information out there that it has disadvantages too. The biggest disadvantage is the fact that you get two objects that appear 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.

I'm going to write an essay discussing this in more detail. When it's done, I'll put it up on the book's web site. It will compare the two approaches and discuss the pros and cons.

Bill Venners: The reason I have used getClass in the past is because I don't know what is going to happen in subclasses. I can't predict that when I am writing my class. It seemed risky to me to use instanceof. If I used instanceof and someone passed a subclass instance to my superclass equals method, I would determine semantic equality by comparing only fields that exist in the superclass. I'd be ignoring any fields declared in subclasses, and it seems like they could be important to the notion of semantic equality for the subclass.

The other way to look at it I guess is that using instanceof in a superclass equals method makes it harder to write subclasses, because equals is supposed to be symmetric. If you call the subclass's equals method implementation, passing in an instance of the superclass, it must return the same result as if you passed the subclass instance to the superclass's equals method.

Josh Bloch: Yes. You are correct in saying that using getClass in equals makes it much easier to preserve the equals contract, but at what cost? Basically, at the cost of violating the Liskov substitution principle and the principle of least astonishment. You write something that obeys the contract, but whose behavior can be very surprising.

<<  Page 17 of 19  >>


Sponsored Links



Google
  Web Artima.com   
Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us