• Post Reply Bookmark Topic Watch Topic
  • New Topic

WHEN to override equals() and hashcode()  RSS feed

 
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Everyone,

Forgive me if this is a stupid question. I've read lots and lots of articles on how to override these two methods equals and hashCode in my own object classes but I sure can't find when I should do so. In terms of the Collection concrete classes, are we talking the ones built from Map and Set interfaces? Or should I only be concerned with the classes that have *hash* in the class name? Some please clue me in. Thanks so much.

Chris

PS: What's the deal with using prime numbers in the hashCode() method or making the collection capacity a prime number? Isn't the JVM smart enough to efficiently put an object in a bucket or is this much ado about nothing - an obsolete coding technique?
 
Ranch Hand
Posts: 1296
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I would say override equals() whenever you have two objects that can be meaningfully equal without being the same instance. For instance if you have one Pen object that is 66% full of black ink, it can be used interchangably with another Pen object that is 66% full of black ink. It doesn't have to be the same Pen - you really don't care if it is the same Pen or not - they are essentially equal. Override hashCode() any time you overide equals()

Isn't the JVM smart enough to efficiently put an object in a bucket


Note that the JVM doesnt handle this. Essentially internally a HashMap is an array of LinkedLists. The *bucket* is normally computed by a user defined algorithm which is usually something like

bucketIndex = object.hashCode() % array.length;

Where array is the array of LinkedLists.
 
Chris Ringer
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I would say override equals() whenever you have two objects that can be meaningfully equal without being the same instance.

Override hashCode() any time you overide equals()


Ok, thanks for the reply but that didn't clear things up for me...
Let me ask another way. Which methods in which collections will automagically call hashCode() and equals() for me, behind the scene?

A myMap.put(myObject.key, myObject)? a myMap.get()? For a mySet.add() too? What about a mySet.contains()? etc... I'm sure someone out there has a nice matrix they will share so I don't have to reinvent the wheel.

Note that the JVM doesnt handle this (put an object in a bucket).


Huh? If I say myHashSet.put(myObject), I the programmer am certainly not explicitly calling hashCode() on myObject so it must be the compiler / JVM.

bucketIndex = object.hashCode() % array.length;


I'm talking about Collections, not an array. If my hashcode can be a 4 byte int, and my collection size is only 101 buckets, something besides me the programmer figures out how to fit such a large hashCode into much smaller # of buckets.

Regards,

Chris

PS: Where is the "review reply" button on these posts? Or do I just get one chance to get it right?
 
(instanceof Sidekick)
Ranch Hand
Posts: 8791
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You can edit and even delete your own posts using the edit icon - sheet of paper with a pencil.

Interesting question about which collections use which methods. I don't know off the top of my head but the JavaDoc will tell you some important bits. I just peeked at Set and found More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element. Watch out for any that want to use compareTo() as well.
 
Garrett Rowe
Ranch Hand
Posts: 1296
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm talking about Collections, not an array.
Collections classes are just normal java classes. There is no *special* JVM support for Maps or Lists or Sets, only arrays. Internally a java.util.HashMap is implemented using a plain old array. The indices of that array are finite (although as the load of the Map increases, a new larger array is allocated and all the key , value pairs are rehashed and their indices recalculated). I was just trying to point out that none of this is decided by the JVM, only by the algorthms used to implement the data structure.
 
Ranch Hand
Posts: 547
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, thanks for the reply but that didn't clear things up for me...
Let me ask another way. Which methods in which collections will automagically call hashCode() and equals() for me, behind the scene?


Just create a class, override the equals()/hashCode() methods (e.g. adding system out statements) and call the add/contains/remove methods of the various collection types and implementations to see which class calls the hashCode/equals method.
Also compare remove(int index) and remove(Object o). I would expect them to produce different results in termns of calling equals/hashCode.

how about HashSet vs. TreeSet ? From the name i am pretty sure HashSet will call at least the hashCode() method but what about the TreeSet ? And so on...

Pascal
 
author
Sheriff
Posts: 14112
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Every JDK is coming with all the source code, which includes the source code for the collection classes. So if you want to know how they work, that would be the most definitive source for you to find out...
 
Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Pascal, I like your method of exploration. That sounds fun! Though it might get old by the time you probe all the operations on all the collections.
 
Ranch Hand
Posts: 208
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I use the following as a rule-of-thumb:

- override equals() if you ever are using the object as a key in a Map
- override equals() when you want objects to be equal even when they are instantiated at different points in the code.
- override hashCode() whenever you override equals(). This is because if a.equals(b)==true, then a.hashCode()==b.hashCode(), always.

Overriding hashCode() without overriding equals() - no example where this is necessary comes to mind, off the top of my head.
 
Chris Ringer
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Adne,

Thanks for the nudge. I did find my answer in a SCJP book. The Collection classes that implement interface Set or Map expect the object or key object respectively to override equals( ). And if something overrides equals, it must override HashCode( ) of course. (If two objects are considered equal, they must have the same hashCode).

The List classes don't care. They just operate on index.

Chris
[ December 06, 2006: Message edited by: Chris Ringer ]
 
author and iconoclast
Sheriff
Posts: 24217
38
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Chris Ringer:

The List classes don't care. They just operate on index.


Well, the List.contains() method cares, as do remove(), removeAll(), and more methods that compare List elements. They'll all use equals().
 
Chris Ringer
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, I see your point. So, basically, if I write a class and the instantiated objects could possibly be put into a concrete Collection of some type (List, Set, Map), I (we?) need to override equals() and therefore hashCode().

And since I don't know how another programmer might be using my class someday, I basically need to override equals() and hashCode(), even if the class is not currently stored in collections. (Who wants to go back, modify code, unit test, system test, redocument and redeploy, so heck - might as well do it up front).

Also, I found out why hashCode() should multiply values by prime numbers. Sun takes our perfectly good hash code and uses that in a supplemental hash() method to compute the final hash code. In doing so, hash() takes our well distributed hash code and inadvertently creates collisions. The prime numbers help counter this unwanted side effect. Here is the Link.

Thanks to all for helping me. Regards,

Chris

[ December 08, 2006: Message edited by: Chris Ringer ]
[ December 08, 2006: Message edited by: Chris Ringer ]
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!