aspose file tools*
The moose likes Beginning Java and the fly likes equals method in java Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Beginning Java
Bookmark "equals method in java" Watch "equals method in java" New topic
Author

equals method in java

divya chowdhary
Greenhorn

Joined: Nov 03, 2012
Posts: 10
We generally override hashCode() whenever we need to store objects in collection based on hashCode values. Based on the logic objects with same hashCode will store under same bucket. This is OK.
But a contract in java says whenever you override hashCode method you must override equals method too.
When i add an object using add method it calculates the hashCode value and stores the object. Here overriding hashCode method helpful in storing but when will this equals method useful in collections?[size=9]
[/size]
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

The hashcode only tells us what bucket the object will be in if it's there. We still need equals() to compare the objects in that bucket to see if any of them are the one we're looking for.

HashCode() and equal() are so often used together that you should always override both whenever you're overriding one. There's no good reason not to, and generally it's required.
divya chowdhary
Greenhorn

Joined: Nov 03, 2012
Posts: 10
So hashCode method is helpful in storing the objects where as equals method helps in retrieving objects from the collection. Am i right?
Also the usage of these methods will remain same in all hash based collections or will these functionality differ from collection to collection?
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39387
    
  28
divya chowdhary wrote: . . . But a contract in java says whenever you override hashCode method you must override equals method too. . . .
No, it doesn’t. It says that if you override equals you must override hashCode too. That is the other way round. It is probably a good idea to override both together all the time, but the contract permits you to override hash and not override equals.
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

divya chowdhary wrote:So hashCode method is helpful in storing the objects where as equals method helps in retrieving objects from the collection. Am i right?


hashCode() is used for storing (to determine which bucket to put it into) and for retrieving (for determining which bucket to look for it in).

equals() is used for storing (if the collection doesn't allow duplicates, to see if an equivalent object is already present within the bucket that hashCode() selected) and for retrieving (to find the specific object we're looking for in the bucket selected by hashCode().

Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 8008
    
  22

divya chowdhary wrote:But a contract in java says whenever you override hashCode method you must override equals method too.

Basically, the two work together, for all the reasons already given. Either don't override either, or override both; otherwise you're setting yourself up for a pile of unnecessary documentation.

Winston

Isn't it funny how there's always time and money enough to do it WRONG?
Articles by Winston can be found here
divya chowdhary
Greenhorn

Joined: Nov 03, 2012
Posts: 10
Campbell Ritchie wrote:
divya chowdhary wrote: . . . But a contract in java says whenever you override hashCode method you must override equals method too. . . .
No, it doesn’t. It says that if you override equals you must override hashCode too. That is the other way round. It is probably a good idea to override both together all the time, but the contract permits you to override hash and not override equals.


In the java docs put method was defined as
"Associates the specified value with the specified key in this map. If the map previously contained a mapping for this key, the old value is replaced."

I have developed a sample program to check this functionality. here i have just override hashCode method but not equals. So it considers the default equals method implementation and stores the object. As a result two objects with same key is stored which is a meaningless. But when i override both methods the statement what was said in java docs getting true. How is it behaving? Is there any wrong in my knowledge or put method works properly according to specification only when we override both the methods?

Also why it is saying that c1.equals(c3) is false even though the hashcode is same for both objects when i won't override equals.

import java.util.*;
class Maps
{
public static void main(String[] args)
{
Car c1= new Car("honda");
Car c2= new Car("bmw");
Car c3= new Car("honda");
Person p1= new Person("a");
Person p2= new Person("b");
Person p3= new Person("c");

HashMap<Car, Person> hs = new HashMap<Car, Person>();
hs.put(c1,p1);
hs.put(c2,p2);
hs.put(c3,p3);
System.out.println(hs.size());
Set s = hs.keySet();
Iterator itr= s.iterator();
while(itr.hasNext()){
Object key= itr.next();
Object value= hs.get(key);
System.out.println(((Car)key).name+" "+((Person)value).name);
}
System.out.println(c1.equals(c3));
}
}
class Car
{
String name;
Car(String name){
this.name=name;
}
public int hashCode(){
return 9+(this.name.length());}
public boolean equals(Object obj){
if(this.name.equals(((Car)obj).name))
return true;
else
return false;
}
};
class Person
{
String name;
Person(String name){
this.name=name;
}

};
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39387
    
  28
divya chowdhary wrote: . . .
In the java docs put method was defined as’t over
"Associates the specified value with the specified key in this map. If the map previously contained a mapping for this key, the old value is replaced."
Which is totally different from what I said earlier.


I have developed a sample program to check this functionality. here i have just override hashCode method but not equals. So it considers the default equals method implementation and stores the object. As a result two objects with same key is stored which is a meaningless.
No, it isn’t. That is exactly how you have designed your class. Put all my instances as keys in the same bucket but we all get different values. It is behaving exactly as the documentation says. Because the equals method returns false, the put method interprets that as two different keys.
But when i override both methods the statement what was said in java docs getting true. . . .

Also why it is saying that c1.equals(c3) is false even though the hashcode is same for both objects when i won't override equals. . . .
The map class behaved exactly as the documentation said in all instances. When you don’t override the equals() method, but do override hash, the map sees them as looking the same, but not being the same. Like twins. The map sees them as different objects. So does equals(). If you don’t override it, equals uses return other == this; or similar. If you override both, then they cease to be twins. They come along to the map saying, “We are not twins, we don’t simply look the same, we are both the same.” If you wrote the class, then you define what “same” means, in the equals method.

If you really want to see things go wrong, try overriding equals and not overriding hash

By the way, that equals method in Car does not fulfil the requirements for the general contract, because it will not accept every kind of Object without any Exceptions.
divya chowdhary
Greenhorn

Joined: Nov 03, 2012
Posts: 10
In my last example both c1, c3 objects have same hash code values but why is it showing the result "false" when comparing "c1==c3", as the "==" returns true when both values are same?

Finally what is the big mistake in not overriding hashCode method when we override equals method? Is the only reason behind this is the bad design of storing equal objects in different buckets or any performance issues
Mansukhdeep Thind
Ranch Hand

Joined: Jul 27, 2010
Posts: 1157

divya chowdhary wrote:In my last example both c1, c3 objects have same hash code values but why is it showing the result "false" when comparing "c1==c3", as the "==" returns true when both values are same?


== test returns true only when both the references point to the same object, not the same value. Try this:



See the difference for yourself. What do the statements print and why?


~ Mansukh
Mansukhdeep Thind
Ranch Hand

Joined: Jul 27, 2010
Posts: 1157

Divya wrote: Finally what is the big mistake in not overriding hashCode method when we override equals method? Is the only reason behind this is the bad design of storing equal objects in different buckets or any performance issues


Well, there are lots of issues that you may run into when you override public boolean equals(Object object) without overriding public int hashCode() of the java.lang.Object class.

But for understanding the gravity of the reasons of sticking to this equals() hashCode() contract, you have to understand the concepts of equality and hash code separately first. Later I will merge the two concepts with an example to answer your query, or rather lead you to the answer. But first , observe what happens when you run the above code. Why is that happening?
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39387
    
  28
That is not a good example; if Integer objects are cached up to 0x0400 that program will behave differently from the minimum size of cache.
divya chowdhary
Greenhorn

Joined: Nov 03, 2012
Posts: 10
@Mansukhdeep Thind

First of all thanks for your explanation in clarifying me the working of "==". With the earlier explanations from "Jeff Verdegan, Campbell Ritchie" i have understood the functionality of these two methods and how the functionality will be when we override hashCode method but not equals. But still i have some interest in knowing the problems that lies behind overriding equals but not hashCode. That's why i have posted it as my last question...
Mansukhdeep Thind
Ranch Hand

Joined: Jul 27, 2010
Posts: 1157

Campbell Ritchie wrote:That is not a good example; if Integer objects are cached up to 0x0400 that program will behave differently from the minimum size of cache.


Yes, I know that Ritchie. Let me take her through with her doubt first. Then I will tell her about this unique behavior too.
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39387
    
  28
It is easy enough to try out your Car class by commenting out the hash code method.
Mansukhdeep Thind
Ranch Hand

Joined: Jul 27, 2010
Posts: 1157

Now observe carefully:



I put the (c1,p1) pair in the map. Yet, when I am trying to retrieve it using an equal object, I am unable to find person name divya. What just happened?
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39387
    
  28
Apart from the fact that your equals() method is written incorrectly?
Mansukhdeep Thind
Ranch Hand

Joined: Jul 27, 2010
Posts: 1157

Campbell Ritchie wrote:Apart from the fact that your equals() method is written incorrectly?


What's wrong with my implementation?
Paul Clapham
Bartender

Joined: Oct 14, 2005
Posts: 18643
    
    8

You made the common beginner's mistake of using == to compare two Strings for equality of contents instead of the equals() method.
Mansukhdeep Thind
Ranch Hand

Joined: Jul 27, 2010
Posts: 1157

Paul Clapham wrote:You made the common beginner's mistake of using == to compare two Strings for equality of contents instead of the equals() method.




OK Now Paul? Or is there something still missing?
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Mansukhdeep Thind wrote:
OK Now Paul? Or is there something still missing?


You made it worse.

You still have the error of using == to compare objects where you should use equals(), and you broke and then removed an optimization at the beginning of the method.



Changing that == to equals() was a mistake, the discovery of which is what I assume led you to comment it out. You should have left it as-is. That's one case where you do want to use ==.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 8008
    
  22

Mansukhdeep Thind wrote:OK Now Paul? Or is there something still missing?

Well, apart from what Jeff told you, my only other observation is that an equals method like that should be defined as final (at least to start with).

Winston
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39387
    
  28
There are lots of ways to write a correct equals method.That version has the advantage that you are not using multiple return. It still has the vulnerability that it will suffer an Exception if either of the fields in the obj object points to null.

Three references: (1) Joshua Bloch Effective Java™, (2) Angelika Langer’s Java FAQ website about equals and hash code, (3) Odersky Spoon and Venners: see this FAQ.
Mansukhdeep Thind
Ranch Hand

Joined: Jul 27, 2010
Posts: 1157

Jeff Verdegan wrote:
Mansukhdeep Thind wrote:
OK Now Paul? Or is there something still missing?


You made it worse.

You still have the error of using == to compare objects where you should use equals(), and you broke and then removed an optimization at the beginning of the method.



Changing that == to equals() was a mistake, the discovery of which is what I assume led you to comment it out. You should have left it as-is. That's one case where you do want to use ==.


No Jeff, when Paul said that I need to use equals() to compare 2 String objects, I thought he was referring to the first if check and not the instance variable comparisons. I referred to Joshua's recipe only. Here is the updated method:


Campbell wrote: That version has the advantage that you are not using multiple return. It still has the vulnerability that it will suffer an Exception if either of the fields in the obj object points to null.


I prefer writing it in multiple lines. Makes the code easier to read.
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39387
    
  28
You do realise that using instanceof can cause the method to lose symmetry if the class is subclassed? Winston G’s technique of marking everything final will preserve symmetry,
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Mansukhdeep Thind wrote:



That null test is pointless. If it's null, instanceof will evaluate to false.



This is still subject to throwing NPE if name or color are allowed to be null.
Mansukhdeep Thind
Ranch Hand

Joined: Jul 27, 2010
Posts: 1157

Campbell Ritchie wrote:You do realise that using instanceof can cause the method to lose symmetry if the class is subclassed? Winston G’s technique of marking everything final will preserve symmetry,


What do you mean when you say that using instanceof can cause the method to lose symmetry if I have a child class that extends Cars? what is meant by method symmetry?
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Mansukhdeep Thind wrote:
Campbell Ritchie wrote:You do realise that using instanceof can cause the method to lose symmetry if the class is subclassed? Winston G’s technique of marking everything final will preserve symmetry,


What do you mean when you say that using instanceof can cause the method to lose symmetry if I have a child class that extends Cars? what is meant by method symmetry?


As explained in the javadocs for equals(), x.equals(y) must return the same value as y.equals(x) for all non-null x and y.

If you create a class SportsCar extends Car, and SportsCar's equals() method tests for instanceof SportsCar, then Car.equals(SportsCar) can return true, but SportsCar.equals(Car) can only return false. Therefore, symmetry can be violated.
Mansukhdeep Thind
Ranch Hand

Joined: Jul 27, 2010
Posts: 1157

Jeff Verdegan wrote:
Mansukhdeep Thind wrote:



That null test is pointless. If it's null, instanceof will evaluate to false.


Roger that.

Jeff Verdegan wrote:

This is still subject to throwing NPE if name or color are allowed to be null.


How to overcome this? Do I put a null check in the constructor before initializing them or throw a NPE if any of these is a null value inside the equals method?
Mansukhdeep Thind
Ranch Hand

Joined: Jul 27, 2010
Posts: 1157

Jeff Verdegan wrote:
Mansukhdeep Thind wrote:
Campbell Ritchie wrote:You do realise that using instanceof can cause the method to lose symmetry if the class is subclassed? Winston G’s technique of marking everything final will preserve symmetry,


What do you mean when you say that using instanceof can cause the method to lose symmetry if I have a child class that extends Cars? what is meant by method symmetry?


As explained in the javadocs for equals(), x.equals(y) must return the same value as y.equals(x) for all non-null x and y.

If you create a class SportsCar extends Car, and SportsCar's equals() method tests for instanceof SportsCar, then Car.equals(SportsCar) can return true, but SportsCar.equals(Car) can only return false. Therefore, symmetry can be violated.


Is marking it as final the only way to prevent that problem? Or is there another way too?
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39387
    
  28
Yes. I know of two ways:-
You can mark the class final, which is probably better.
You can use getClass instead of instanceof.
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Mansukhdeep Thind wrote:
Jeff Verdegan wrote:

This is still subject to throwing NPE if name or color are allowed to be null.


How to overcome this? Do I put a null check in the constructor before initializing them


That's one way. But you don't do that to fix equals(). You do it if your design dictates that those fields cannot be null.

or throw a NPE if any of these is a null value inside the equals method?


No, equals should not throw any excpetions. And throwing an NPE to avoid an NPE is not particularly productive. If the semantics of your object allow those fields to be null, then, obviously, you have to test for them being null in equals() before you dereference them.
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Mansukhdeep Thind wrote:
Jeff Verdegan wrote:
If you create a class SportsCar extends Car, and SportsCar's equals() method tests for instanceof SportsCar, then Car.equals(SportsCar) can return true, but SportsCar.equals(Car) can only return false. Therefore, symmetry can be violated.


Is marking it as final the only way to prevent that problem? Or is there another way too?


You can mark the method final.

Or you can document that Car uses instanceof Car, and therefore every subtype must also use instanceof Car if it overrides equals().

Or you can use getClass() instead (as long as no supertype of Car uses instanceof).

As with so many other things, which approach is "best" depends on the semantics of your class. For instance, classes in the Collections Framework have to use instnaceof List/Set/Map. But for some other classes, it might never make sense for an instance of a subclass to be equal to an instance of a parent class, so you'd use getClass().
Mansukhdeep Thind
Ranch Hand

Joined: Jul 27, 2010
Posts: 1157

I think I shall stick to Winston's advice for now. I will mark it as final so that there is no chance of the symmetry being ruptured. And as for the null value problem, let us assume that the car name and color can not be null. So, here it is:



Makes sense now?
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 8008
    
  22

Mansukhdeep Thind wrote:I think I shall stick to Winston's advice for now.

Fine, but do read the links that Campbell gave you. As Jeff said, the way you write equals() depends entirely on how you want it to work; there is no 'right' or 'wrong' about it (well actually, there are plenty of ways to write it wrong, but that's outside what we're talking about here ); final is just a way of ensuring that nobody can accidentally foul up your equals() contract.

Another way of ensuring symmetry is with a canEqual() method (explanation is near the bottom of the page). Yet another thing worth knowing about.

Winston
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 8008
    
  22

Mansukhdeep Thind wrote:I think I shall stick to Winston's advice for now.

And, at the risk of muddying the waters even more, I like to add an extra typed equalTo() method, viz:then your equals() method becomes:and you can pretty much cookie-cutter it for any subclass (changing 'ThisClass' as appropriate of course).

Winston
Mansukhdeep Thind
Ranch Hand

Joined: Jul 27, 2010
Posts: 1157

I don't think Divya is coming back with any more of equals() / hashCode() doubts when she reads all this. Or may be she will. Anyways, let's see if she has understood the importance of equal objects should have equal hash code rule which is why I wrote the code in the first place.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 8008
    
  22

Mansukhdeep Thind wrote:I don't think Divya is coming back with any more of equals() / hashCode() doubts when she reads all this...let's see if she has understood the importance of equal objects should have equal hash code rule which is why I wrote the code in the first place.

Agreed. Fun stuff though. Who'd have thought that something that seems so simple could end up being such a PITA?

Winston
 
jQuery in Action, 2nd edition
 
subject: equals method in java