The very first question which comes to my mind is - What exactly the difference between equals() and ==. Below is the small code which can answer this question
public boolean equals(Object o) - this method is declared in Object class and == is an operator. == and equals() always check for reference equality i.e it will compare whether two references are equal or not. But in case of String and Wrapper classes equals will always check for object value equality. Lets have a look on an example:
public class TestEqual { String name; TestEqual(String name) { this.name = name; } public static void main(String args[]) { TestEqual t1 = new TestEqual("Ankit"); TestEqual t2 = new TestEqual("Ankit"); System.out.println("t1==t2 results to" + (t1 == t2)); System.out.println("t1.equals(t2)results to" + (t1.equals(t2))); } }
In both the cases output will be false. If you try to print t1.hashcode() and t2.hashcode() alone you will get two different hashcodes.
But what if I want to change this behavior. The answer is, I need to override equals() method which happens in String and all the wrapper classes. Lets have a look on the example
In both the cases output will be true. If you try to print t1.hashcode() and t2.hashcode() alone you will get same hashcodes.
public static void main(String args[]) { String t1 = “Ankit”; String t2 = "Ankit"; System.out.println("t1==t2 results to"+(t1==t2)); System.out.println("t1.equals(t2)results to"+(t1.equals(t2))); System.out.println(t1.hashCode() +"," +t2.hashCode() ); }
In both the cases output will be true. If you try to print t1.hashcode() and t2.hashcode() alone you will get same hashcodes.
Lets override equals() method for our class TestEqual which I have mentioned above:
public boolean equals(Object test) { if (this.name == ((TestEqual)test).name) { return true; } else return false; } }
Now try printing the output for these two statements
System.out.println("t1==t2 results to"+(t1==t2)); // This will give you false System.out.println("t1.equals(t2)results to"+(t1.equals(t2))); // This will give you true
You must be thinking that’s all we have to do and our code will work fine. But still we are missing a very important concept. Any guesses – we forgot to override hashcode() which is also declared in the Object class.
But what is the need behind overriding the hashcode() method. Overriding the equals method has already solved my problem. Still we can't ignore the contract between equals() and hashcode() methdod which states that –
If equals says that two object references are equal then their hashcode will always be equal but if equals says that two object references are NOT equal then their hashcode may or may not be equal. Again lets have a look on an example which will justify the need of overriding hashcode method:
TestEqual t1 = new TestEqual("Ankit"); TestEqual t2 = new TestEqual("Ankit"); Set<TestEqual> strset = new HashSet<TestEqual>(); strset.add(t1); strset.add(t2); System.out.println("strset.contains check: " + strset.contains(new TestEqual("Ankit"))); public boolean equals(Object test) { if (this.name == ((TestEqual)test).name) { return true; } else return false; } }
The output will be strset.contains check: false in this case. Oops but we override the equals() method. But that doesn’t hold good in this case. The reason is hashcode of t1, t2 and new TestEqual() object are still different and in order to make them equal, hashcode() method should be overridden. Once you override hashcode method you will get the desired output i.e strset.contains check: true
Public int hashCode() { return 1; }
Conclusion: equals and == always check for reference equality. In order to make equals() to check for Object value equality we need to override equals() and hashcode() method which happens in String and all the wrapper classes. J
Mystery is really resolved.
ReplyDeleteGood one, Thanks for sharing.
ReplyDelete