Wednesday, May 7, 2014

What is the contract between hashCode() and equals() method?

Lets take an example of Book.

class Book{
String name ;
int bookid;
public Book(String name,int bookid) {
this.name=name;
this.bookid=bookid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getBookid() {
return bookid;
}
public void setBookid(int bookid) {
this.bookid = bookid;
}
}


Now lets create books (Book objects) and store it in hashtable.

                Book book1 = new Book("Java", 123);
Book book2 = new Book("C++", 456);
                Book book3 = new Book("Java", 123);

Hashtable<Book, String> ht = new Hashtable<Book, String>();
ht.put(book1, book1.getName());
ht.put(book2, book2.getName());

From the above code we can see that a Java book and C++ book is added to the hashtable. Lets check the equality of the two objects.

               System.out.println("Book1 equals Book2 :" + book1.equals(book2));  =  false

System.out.println("Book1 equals Book3 :" + book1.equals(book3)); = false



So though book1 and book3 are same equals() method returns false. So we should override the equals of method in the Book class.

@Override
public boolean equals(Object o) {
Book book = (Book)o;
return (this.bookid == book.bookid && this.name.equals(book.name));
}

Now we are checking whether book ids and the names match in the overridded equals() method.

So book1 and book3 will be equal now as both have name 'Java' and id '123'

               System.out.println("Book1 equals Book3 :" + book1.equals(book3)); = true

Now we know that book1 and book3 are same. So lets try to get the book1 from the hashtable.


                System.out.println(ht.get(book3)); = null
     
                System.out.println("Book 1 hashcode :" + book1.hashCode());  = 1021653256

System.out.println("Book 2 hashcode :" + book2.hashCode());  = 1794515827

System.out.println("Book 3 hashcode :" + book3.hashCode());   = 1167165921
 
ht.get(book3) method will return null. If you think if book1 and book3 are same then ht.get(book3) should have returned 'Java', then you are missing something. hashCode() method comes into picture now.

In my previous post i have explained what is the use of hashCode(). So now hashCode(book3) will be calculated which is 1167165921  and it will check whether there is a any entry for the key equals(1167165921)?. So it will return false.

book1 and book3's hashCode should match in order to retrive book1 by giving book3 as the key.

As we have not overridden the hashCode() method in the Book class it will never find a matching value.

@Override
public int hashCode() {
return this.bookid;
}

Lets try again to check whether book object is there?

      
System.out.println("Book1 equals Book3 :" + book1.equals(book3)); = true

System.out.println("Book 1 hashcode :" + book1.hashCode()); = 123

System.out.println("Book 3 hashcode :" + book3.hashCode()); = 123

System.out.println(ht.get(book3)); = Java.

so to summarize,
1) When two objects are equal, their hashcode should be equal and not vice versa.
2 ) When you override equals() you should override hashCode() method also.

Lets discuss Point 1:

When hashCode() of two objects are equal it is not necessary that they should be equal.

Let us create two book objects:
               Book book1 = new Book("Java", 123);

Book book2 = new Book("JSON", 456)

Now override hashCode() method in Book.

@Override
public int hashCode() {
return this.name.length();
}

The hashcode of book1 and book2 are same, but they are not equal.

   System.out.println("Book1 equals Book2 :" + book1.equals(book2)); = false
System.out.println("Book 1 hashcode :" + book1.hashCode()); = 4

System.out.println("Book 2 hashcode :" + book2.hashCode()); = 4
  

             

No comments:

Post a Comment