Implementing hashcode on java classes containing collections
I have a class that contains a collection. Two instances of the class are equal if the contents of the collection are equal. While I am building my data structure, I store the class in a HashSet and the contents of the collection change. Changes lead to a change in the hash code value. This seems to cause side effects when my data gets lost in the set. Removing the collection from the hash calculation fixes the problem, but violates the rule that all fields in equals must be used in the hash code.
How would you implement the hash code in this situation?
public class LeveZeroHolder
{
private final Set<LevelOneHolder> orgGroups = new HashSet<LevelOneHolder>();
private final String name;
public LeveZeroHolder(String name, LevelOneHolder og)
{
this.name = name;
orgGroups.add(og);
og.setFA(this);
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null || obj.getClass () != getClass ())
return false;
LeveZeroHolder hobj = (LeveZeroHolder)obj;
return getOrgGroups().equals(hobj.getOrgGroups()) && getName().equals(hobj.getName());
}
@Override
public int hashCode()
{
int rs = 17;
rs = rs * 37 + ((getName() == null) ? 0 : getName().hashCode ());
rs = rs * 37 + ((getOrgGroups() == null) ? 0 : getOrgGroups().hashCode());
return rs;
}
public String getName()
{
return name;
}
public Set<LevelOneHolder> getOrgGroups()
{
return orgGroups;
}
public void addOrgGroup(LevelOneHolder o)
{
o.setFA(this);
orgGroups.add(o);
}
}
source to share
If you mean that when you store objects like a key in a map or in a set, they are lost, you can watch this thread explain why storing changed objects in a set is not good, especially if they change while being held by a set.
Extract from Set
javadoc:
Note. Great care should be taken when mutable objects are used as set items. Set behavior is not specified if the value of an object is changed in a way that affects equal comparisons when the object is an element in the set. A special case of this prohibition is that it is unacceptable for a set to contain itself as an element.
source to share
If your LevelOneHolder collection does affect the uniqueness of your object, you should make the LevelZeroHolder immutable. If you add LevelOneHolder to your LevelZeroHolder, instead of updating the collection, you must return an entirely new LevelZeroHolder with the collection copied from the existing one and linked to the new one you want to add.
This way the hashCode never changes, but you end up with different LevelZeroHolders with different hashcodes. This is probably correct, although you think that the nested collection in the LevelZeroHolder contributes to the uniqueness of this object.
source to share
If you put your object in a data structure where you depend on hashCode or equals () to find it, AND if you change any property of the object (like its name or something in a list in it) when it's already is in this data structure, then you won't find it. Is this your case?
The reason is that when you put an object in such a data structure, it is inserted according to its hashCode at the time of insertion. If in its interior you change something that changes the hashcode, then your object is still stored according to the old hashcode, but when you try to get it and so you calculate its hashCode to see if it is your object, then you get a new hashCode and so you don't see that this is the one you want.
The rule of thumb is that for an object in a data structure that uses the object's hashcode or equals NEVER, modify the object in a way that affects hashCode or equal.
Try using immutable objects instead.
source to share