Java provides extensive list of Collection classes to group similar type of objects. Covering complete Java Collection framework details is huge task and is out of scope for this post. Here in this post, I just wanted to cover one scenario related to collections which use hash codes for storing objects.
Scenario:
Collections allow to store user defined class objects. Once the objects are added into collection, what will happen if the object properties gets updated? Will the object in collection get updated with changed values? Will the object be still searchable in collection?
Lets see below example to get the answers of above questions –
Employee.java: Model class which we want to add into Set.
public class Employee {
private long empId;
private String name;
private int salary;
public Employee(long empId, String name, int salary) {
super();
this.empId = empId;
this.name = name;
this.salary = salary;
}
public long getEmpId() {
return empId;
}
public void setEmpId(long empId) {
this.empId = empId;
}public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (empId ^ (empId >>> 32));
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + salary;
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 (empId != other.empId)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (salary != other.salary)
return false;
return true;
}
@Override
public String toString() {
return "Employee [empId=" + empId + ", name=" + name + ", salary=" + salary + "]";
}
}
ImmutableObjInSet.java: A main class used for testing purpose. Here we will create object of Employee class and add into Set. After adding object we will try to update property of one object and see how it will impact the stored object in Set.
public class ImmutableObjInSet {
public static void main(String[] args) {
Set set = new HashSet();
//Create Employee objects
Employee emp1 = new Employee(10, "Mr. ABC", 10000);
Employee emp2 = new Employee(20, "Ms. PQR", 11000);
Employee emp3 = new Employee(30, "Mr. XYZ", 15000);
//Add Employee objects in Set
set.add(emp1);
set.add(emp2);
set.add(emp3);
//find object in set
System.out.println("[Before updates]Is Employee found? "+set.contains(emp1));
emp1.setSalary(12000);
//Printing employee object to check if the updates are reflected in set
for(Employee emp : set) {
System.out.println(emp);
}
System.out.println("[After updates]Is Employee found? "+set.contains(emp1));
}
}
Output: Above program will give below output.
[Before updates]Is Employee found? true
Employee [empId=10, name=Mr. ABC, salary=12000]
Employee [empId=20, name=Ms. PQR, salary=11000]
Employee [empId=30, name=Mr. XYZ, salary=15000]
[After updates]Is Employee found? false
In above output, salary of emp1 object stored in HashSet is correctly updated to 12000. When we tried to search the modified object in Set using contains()
method, the object is not found and method returned false.
How hash based collections work in this case:
It is recommended to use all object properties to calculate the hash code of object in order to generate different hash code for different state of the objects. So any change is properties value of object result is different hash code.
When the object is stored as Key in HashMap or as value in HashSet, internally HashSet stores it based on the its hash code. Storage location gets decided based on objects hash code. These collections use object’s hash code again to correctly locate the stored elements while searching for particular object.
In this example, when the employee object is added in HashSet, internally HashSet retrieves the hash code of employee object and allocates the space based on the hash code. After the object is added in collection if the object state gets changed, it will generate different hash code. Updated values gets reflected in the object stored the collection as the object reference is same. But when the updated object is searched using contains
method, HashSet tries to search the object as per the new hash code and unable to locate the stored object as object was allocated a storage based on old hash code.
Same scenario is applicable for the keys in HashMap.
Thanks,
Lalit