Contract between equals() and hashCode()
Points To Remember
- Both the method equals() and hashCode() are the methods of Object class, hence available in all the classes.
- Syntax for equals() method in Object class is public boolean equals(Object obj)
- Syntax for hashCode() method in Object class is public int hashCode()
- The equals() method of Object class checks if the two references compared point to same object, returns true if they are same and false if two objects are different. We can override this functionality by our own custom way of comparing objects.
- If the equals() method returns true, then the hashcode() of the two object must be same.
- If hashCode() of two objects are same, it does not mean that the objects should be same.
Concept : equals() & hashCode() method in Object class
First of all lets see what does an equals() method do in java. The equals method in the object class is used to see that if the two object references are pointing to the same object. See how equals() method works. So if two references are pointing to same object then all the member variables of the object must be same in all respect, this means that the hashcode of the two objects must also be same.Let us see How hashCode() method works. The hash code method returns the hash a 16 digit integer number from some internal hashing algorithm.
This is a one way process, which means
- if we know a key then we can generate the hashcode and it will always be the same
- but if we have hashcode, then we cannot find the key from hashcode.
So, we summarize as below.
- If equals returns true, then the hashcode of the two objects must be same.
- If equals returns false, hashcode may or may not be same.
- If hashcode of two objects is same, then equals may may not return true.
Program : Invalid use of hashCode() and equals()
The below program as a problem, it does not follow the contract of equals and hashcode.We override the equals method and say that the two object of Book class are equal if their name is same. So by convention, if the name of two books are same then the hashcode of objects must be same. But in this case the hashcode may vary since we multiply the hashcode of book name with book id, where book id may be different.class Book{ int id; String name; public Book(int id, String name){ this.id = id; this.name= name; } @Override public boolean equals(Object obj){ // Null checks not included. Book book = (Book)obj; if(this.name.compareTo(book.name)==0 ) return true; else return false; } @Override public int hashCode(){ return this.name.hashCode() * this.id; } } class Test{ public static void main(String args[]){ Book book1 = new Book(1,"book"); Book book2 = new Book(2,"book"); Book book3 = new Book(1,"book"); System.out.println("book1.equals(book2) = "+ book1.equals(book2) + " book1.hash= "+book1.hashCode()+ " book2.hash= "+book2.hashCode()); System.out.println("book1.equals(book3) = "+ book1.equals(book3) + " book1.hash= "+book1.hashCode()+ " book3.hash= "+book3.hashCode()); System.out.println("book2.equals(book3) = "+ book2.equals(book3) + " book2.hash= "+book2.hashCode()+ " book3.hash= "+book3.hashCode()); } }
book1.equals(book2) = true book1.hash= 3029737 book2.hash= 6059474 book1.equals(book3) = true book1.hash= 3029737 book3.hash= 3029737 book2.equals(book3) = true book2.hash= 6059474 book3.hash= 3029737
Program : Valid use of hashCode() and equals()
In the above example the problem was that, the two objects that are same according to our implementation should also have returned same hashcode, but it was not so(as shown by the output). So we may correct this by either- changing this.name.hashCode() * this.id; to this.name.hashCode();
- changing if(this.name.compareTo(book.name)==0 ) to if(this.name.compareTo(book.name)==0 && this.id == book.id)
class Book{ int id; String name; public Book(int id, String name){ this.id = id; this.name= name; } @Override public boolean equals(Object obj){ // Null checks not included. Book book = (Book)obj; if(this.name.compareTo(book.name)==0 && this.id == book.id) return true; else return false; } @Override public int hashCode(){ return this.name.hashCode() * this.id; } } class Test{ public static void main(String args[]){ Book book1 = new Book(1,"book"); Book book2 = new Book(2,"book"); Book book3 = new Book(1,"book"); System.out.println("book1.equals(book2) = "+ book1.equals(book2) + " book1.hash= "+book1.hashCode()+ " book2.hash= "+book2.hashCode()); System.out.println("book1.equals(book3) = "+ book1.equals(book3) + " book1.hash= "+book1.hashCode()+ " book3.hash= "+book3.hashCode()); System.out.println("book2.equals(book3) = "+ book2.equals(book3) + " book2.hash= "+book2.hashCode()+ " book3.hash= "+book3.hashCode()); } }
book1.equals(book2) = false book1.hash= 3029737 book2.hash= 6059474 book1.equals(book3) = true book1.hash= 3029737 book3.hash= 3029737 book2.equals(book3) = false book2.hash= 6059474 book3.hash= 3029737
No comments: