,

Wednesday 11 February 2015

equals and hashcode method

Why it is necessary to override equals and hashcode?

This is one of the popular interview question. So lets understand the same practically.
I have class Employee having id and name member variables and I am trying to put few Employee object as key in HashMap.
In this example I am not overriding hashcode and equals method.

Demo1:(Without hashcode and equals)

package com.a;
import java.util.HashMap;
/**
 *
 * @author Ganesh.Rashinker
 *
 */
class Employee {
private int id;
private String name;

public Employee(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + "]";
}
}

public class Demo1 {
public static void main(String[] args) {
HashMap<Employee, String> map = new HashMap<Employee, String>();
Employee emp1 = new Employee(1, "John1");
Employee emp2 = new Employee(2, "Tom2");
Employee emp3 = new Employee(3, "Tom3");
Employee emp4 = new Employee(4, "Tom4");
map.put(emp1, "first");
map.put(emp2, "second");
map.put(emp3, "third");
map.put(emp4, "fouth");
System.out.println(map);
}
}

Possible Output 1:
{Employee [id=2, name=Tom2]=second, Employee [id=3, name=Tom3]=third, Employee [id=1, name=John1]=first, Employee [id=4, name=Tom4]=fouth}



Possible Output 2:
{Employee [id=3, name=Tom3]=third, Employee [id=4, name=Tom4]=fouth, Employee [id=2, name=Tom2]=second, Employee [id=1, name=John1]=first}




From the above output it is clear that every time you execute the code , it will generate different hashcode for your objects and they will go in different buckets.
The hashcode implementation of Object class is native.

In the next example , we are overriding only hashcode.

Demo 2:(With hashcode and Without equals)


package com.a;
import java.util.HashMap;

/**
 *
 * @author Ganesh.Rashinker
 *
 */
class Employee {
private int id;
private String name;

public Employee(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + "]";
}
}
public class Demo1 {
public static void main(String[] args) {
HashMap<Employee, String> map = new HashMap<Employee, String>();
Employee emp1 = new Employee(1, "John1");
Employee emp2 = new Employee(2, "Tom2");
Employee emp3 = new Employee(3, "Tom3");
Employee emp4 = new Employee(4, "Tom4");
map.put(emp1, "first");
map.put(emp2, "second");
map.put(emp3, "third");
map.put(emp4, "fouth");
System.out.println(map);
}
}





Output: 
{Employee [id=2, name=Tom2]=second, Employee [id=1, name=John1]=first, Employee [id=4, name=Tom4]=fouth, Employee [id=3, name=Tom3]=third}




As we have overriden hashcode and the calculation of hashcode value is on the basis of id and name , everytime you execute it will generate the same hashcode and it will go in the same bucket.

Now lets try to understand why we need equals method.

Demo 3:(With hashcode and Without equals)

package com.a;
import java.util.HashMap;

/**
 *
 * @author Ganesh.Rashinker
 *
 */
class Employee {
private int id;
private String name;

public Employee(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + "]";
}
}
public class Demo1 {
public static void main(String[] args) {
HashMap<Employee, String> map = new HashMap<Employee, String>();
Employee emp1 = new Employee(1, "John1");
Employee emp2 = new Employee(1, "John1");
map.put(emp1, "first");
map.put(emp2, "second");
System.out.println(map);
}
}




Output:
{Employee [id=1, name=John1]=second, Employee [id=1, name=John1]=first}




From the above output it is clear that even though the contents of the both objects are same and hashcode is also same , they are added in same bucket. The problem here is both the objects are added. The reason is that the Object class has the equals implementation which checks the address and as these are two different objects they are different.

Now lets override equals method.

Demo 4:(With hashcode and equals)

package com.a;
import java.util.HashMap;

/**
 *
 * @author Ganesh.Rashinker
 *
 */
class Employee {
private int id;
private String name;

public Employee(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + "]";
}
}
public class Demo1 {
public static void main(String[] args) {
HashMap<Employee, String> map = new HashMap<Employee, String>();
Employee emp1 = new Employee(1, "John1");
Employee emp2 = new Employee(1, "John1");
map.put(emp1, "first");
map.put(emp2, "second");
System.out.println(map);
}
}

Output:
{Employee [id=1, name=John1]=second}






Now you can see that only one object has been added.

Conclusion: 
It is neccessary to override equals and hashcode function for the class which is added as key in HashMap.

No comments:

Post a Comment