This tutorial explains the equals() and hashcode() method in simple terms. It is one of the confusing questions on the Java developer’s mind. The common questions asked about these methods are:
- What is equals() method and why should I override that in our classes?
- What is hashcode() method?
- Why should I always override hashcode() when overriding equals() method?
Also Read :
equals()
I assume you might already be knowing basics of objects and strings in Java. You might come across several situations, where you might need to compare if two things are equal. For this, java provides equals() method which compares if two objects are equal(Read : Comparable vs Comparator Interface in Java ).
Take this simple example:
public class StrEquals { public static void main(String[] args) { Object obj1 = new Object(); Object obj2 = new Object(); System.out.println(obj1.equals(obj2)); obj1 = obj2; System.out.println(obj1.equals(obj2)); } }
The code does nothing fancy except that it uses equals() method for comparing two objects. The first print statement will print false because the two objects created are different. However, below that print statement I have assigned one object to another and hence both objects point to the same location in memory. Hence equals() method when invoked, returns true in the second case.
This is Java Object’s open source implementation of equals() method.
public boolean equals(Object obj) { return (this == obj); }
So can I use this object equals() method for all my classes. Will that work? Answer is NO most of the times. Lets see that with an example.
public static void main(String[] args) { String str1 = "test"; String str2 = "test"; System.out.println(str1.equals(str2)); }
The objective is to compare if two string contents are equal and not to compare two string objects. Without reading further, pause and think for a second if the default object implementation of equals() will work on Strings?. Hope you gave some thought into it. You would have figured that default Object equals() method will not work. So what we do?.
Now we get into overriding equals() method. Since our objective is to compare two string equality of string contents rather than the two string objects, as a programmer, we are supposed to override this equals() method and provide our own implementation.
Java open source code of String equals() method goes like this.
public boolean equals(Object strObject) { if (this == strObject) { return true; } if (strObject instanceof String) { String anotherString = (String) strObject; int n = count; if (n == anotherString.count) { char v1[] = value; char v2[] = anotherString.value; int i = offset; int j = anotherString.offset; while (n-- != 0) { if (v1[i++] != v2[j++]) return false; } return true; } } return false; }
Don’t go nuts over trying to understand the above code. This is just to illustrate the point that the default Object implementation of equals() method will not serve our purpose here and so have to override the equals() method in our classes and provide implementation according to the needs. Hope that makes it clear on the need to override equals() method.
Note: One thing to keep in mind is that, if you don’t specify an equals() method in your class, Java will use the default equals() method in Object class as all objects are derived from the parent Object class.
I hope this makes you excited to know about hashcode() as well.
hashcode()
Hashcode() method does nothing special rather than returning hash code value for the object. If you haven’t heard of hashcode, think that this method would return distinct integers for distinct objects.
Now coming to the most important question, why is it always advisable to override hashcode() when overriding equals() method?. Java has a contract in its JavaDocs which states that if two objects are equal according to equals(Object), then calling hashcode() method on those objects must also produce the same integer result. In other words, if object1.equals(object2) is true, then object1.hashcode() == object2.hashcode() must also be the same. Enough of theory, lets get to an example.
public class StrEquals { private int str1; StrEquals(int s1){ str1 = s1; } public static void main(String[] args) { StrEquals equals = new StrEquals(10); StrEquals equals1 = new StrEquals(20); StrEquals equals2= new StrEquals(30); HashSet< StrEquals> map1 = new HashSet<StrEquals>(); map1.add(equals); map1.add(equals1); map1.add(equals2); System.out.println(map1.contains(new StrEquals(10))); } @Override public boolean equals(Object obj) { StrEquals equals = (StrEquals) obj; if (this.str1 == equals.str1){ return true; } else return false; } }
What will the print statement output? False!! Why?
Because when we override equals() method, we override the general conditions used for equality of objects with our own custom logic. Hence when we call some methods such as “contains” just as in this case, Java internally uses both hashcode() and equals() method, it causes some bugs difficult to trace. Also we broke the contract which states that if two objects() are equal using equals(), then their hash codes must also be the same.
In our case, though we are calling the same new StrEquals(10) in contains method, it gets two different hash values as Java considers them to be different objects. Its our duty to say to Java that these are one and the same using our own overridden method of hashcode() in our classes.
Summary
To avoid these kinds of untraceable bugs and to follow Java contract, we ALWAYS override hashcode() method when we override equals() method. Hope you enjoyed reading my thoughts on overriding equals() and hashcode(). Please post your comments/correction if any. Thanks for reading.
This article is originally published at Java tutorials – Lets jump into the ocean, re-posted here with authors permission and as part of the JBC program.