Example of equals and hashcode method in java
This document explains :Why equals and hashcode methods are require and how to implement them.
If you want to use a class as a key in MAP/SET, provide proper hashcode() and equals() method implementation for that class.
Reason: If you don't provide implementation for these methods class will inherit these from superclass implementation of these methods(generally Object class) and map/set may behave incorrectly.
Lets’ take an example of employee class
Employee.java
public class Employee
{
String employeeId;
enum EmpType{FULLTIME, PARTTIME, INTERN};
String type;
String joiningYear;
public Employee(String empId, String type, String jy)
{
this.employeeId = empId;
this.type = type;
this.joiningYear = jy;
}
public void show()
{
System.out.println("Employee ID : "+employeeId + " Employee Type "+ type+" joining year "+joiningYear);
}
@Override
public String toString()
{
return employeeId + " "+type + " "+joiningYear;
}
}
MainClass1.java
import java.util.HashMap;
import java.util.Map;
public class MainClass1 {
public static void main(String[] args)
{
Map<Employee,Float> map = new HashMap<Employee, Float>();
Employee e1 = new Employee("Mayank Sharma", EmpType.FULLTIME.toString(), "2013");
Employee e2 = new Employee("Nikhil Kumar", EmpType.INTERN.toString(), "2014");
Employee e3 = new Employee("Love Sharma", EmpType.PARTTIME.toString(), "2013");
Employee e4 = new Employee("Kapil Kumar", EmpType.FULLTIME.toString(), "2002"); Employee e5 = new Employee("Neeraj Panwar", EmpType.INTERN.toString(), "2014");
Employee e6 = new Employee("David Buther", EmpType.PARTTIME.toString(), "2011");
Employee e7 = new Employee("David Buther", EmpType.PARTTIME.toString(), "2011");
map.put(e1, (float) 500000);
map.put(e2, (float) 50000);
map.put(e3, (float) 400000);
map.put(e4, (float) 1500000);
map.put(e5, (float) 50000);
map.put(e6, (float) 80000);
map.put(e7, (float) 90000);
for(Employee employee: map.keySet())
{
employee.show();
System.out.println(map.get(employee));
}
}
}
Output:
Employee ID : David Buther Employee Type PARTTIME joining year 2011
90000.0
Employee ID : Neeraj Panwar Employee Type INTERN joining year 2014
50000.0
Employee ID : Kapil Kumar Employee Type FULLTIME joining year 2002
1500000.0
Employee ID : Nikhil Kumar Employee Type INTERN joining year 2014
50000.0
Employee ID : Love Sharma Employee Type PARTTIME joining year 2013
400000.0
Employee ID : David Buther Employee Type PARTTIME joining year 2011
80000.0
Employee ID : Mayank Sharma Employee Type FULLTIME joining year 2013
500000.0
Here object “e7” and “e6” have same hash code, but e7 should have override the e6 but map contains both e6 and e7 which shows that but e6 and e7 should be same since they have same value set.
Now override equals method in Employee class:
@Override
public boolean equals(Object o)
{
if(o == this)
return true;
if(!(o instanceof Employee1))
{
return false;
}
Employee1 employee1 = (Employee1)o;
return this.employeeId.equals(employee1.employeeId)
&& this.type.equals(employee1.type)
&& this.joiningYear.equals(employee1.joiningYear);
}
Add try to run the same program.
You will get same output. It is because hashcode() is not overridden in employee class and we are using the same previous hashcode which says that two different object will have same hashcode.
Now lets, override the hashcode() in Employee class :
@Override
public int hashCode()
{
return 42;
}
All the objects have same hash code, so they all will added in a particular entry of linked list and hence form a linked list.
Now run the program.
Wow. You will get the desired output.
Output:
Employee ID : Mayank Sharma Employee Type FULLTIME joining year 2013
500000.0
Employee ID : Nikhil Kumar Employee Type INTERN joining year 2014
50000.0
Employee ID : Love Sharma Employee Type PARTTIME joining year 2013
400000.0
Employee ID : Kapil Kumar Employee Type FULLTIME joining year 2002
1500000.0
Employee ID : Neeraj Panwar Employee Type INTERN joining year 2014
50000.0
Employee ID : David Buther Employee Type PARTTIME joining year 2011
90000.0
There is no duplicate entry for employee with employee name : David Buther
You can provide following implementation of hashcode for better performance:
@Override
public int hashCode()
{
int result =17;
result = 31* result + employeeId.hashCode();
result = 31*result + type.hashCode() ;
result = result* 31 +joiningYear.hashCode();
return result;
}
This method avoid collision and final map will not looks like a linked list as in the previous case.
Where the equals and hashcode methods are use?
Let’s take the HashMap put method implementation:
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
And here is the implementation of hash() :
final int hash(Object k) {
int h = hashSeed;
if (0 != h && k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
}
h ^= k.hashCode();
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}