Reputation: 681
I have an Employee class having 2 attributes id and name. I am overriding the hashcode and equals method as given below.
Employee.java:
import java.util.Objects;
public class Employee {
private int id;
private String 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() {
return Objects.hash(id, name);
}
@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 + "]";
}
}
And now i have a test class where i am creating an object of employee class with name "Chris Gayle" and adding it to HashSet. After that i am modifying the name of this existing employee object to "Kieron Pollard" and i am adding this modified employee object again to hashset.
TestSet.java
import java.util.HashSet;
import java.util.Set;
public class TestSet {
public static void main(String[] args) {
Set<Employee> hashSet = new HashSet<Employee>();
Employee emp1 = new Employee();
emp1.setId(1);
emp1.setName("Chris Gayle");
hashSet.add(emp1);
System.out.println(hashSet);
emp1.setName("Kieron Pollard");
hashSet.add(emp1);
System.out.println(hashSet.size());
System.out.println(hashSet);
}
}
When i print the content of hashset i gives the same employee object two times as given below.
[Employee [id=1, name=Chris Gayle]]
2
[Employee [id=1, name=Kieron Pollard], Employee [id=1, name=Kieron Pollard]]
Since, set doesn't allow duplicate elements but in the output we are getting duplicates in above scenario. So, what is the correct way to handle this kind of behaviour.
Upvotes: 0
Views: 5713
Reputation: 4030
Thanks for bringing this up. You should look how the HashSet
is implemented. Your example also provides a good idea about why immutability is preferred.
Here is what is happening.
HashSet
.HashSet
stored the reference to the object with the hash of the object. Let us say hash is 10 (For id = 1, name = Chris Gayle)HashSet
does not know about the change you made to the object. It holds only the reference but the hash of the object is changed. Let us say it changed to 20 (for id = 1, name = Kieron Pollard).HashSet
added a new entry when you added the same object or the second time.If you try to create a new HashSet with new HashSet<>(hashSet)
then you will see only one object.
Upvotes: 2
Reputation: 21285
You shot yourself in the foot here.
@Override
public int hashCode() {
return Objects.hash(id, name);
}
If hashCode
is defined by the id
& name
& you change the name before adding the object to a HashSet
again, you'll obviously get a duplicate entry. Reminder: the uniqueness of an object is determined by the hashCode
- and that's what HashSet
uses to determine if the object is already in the Set
.
What's your uniqueness criterion? If id
is meant to be unique, use only id
in the hashCode
.
@Override
public int hashCode() {
return Objects.hash(id);
}
Upvotes: 5