- Whenever it is invoked on the same object more than once during
an execution of a Java application, the hashCode method
must consistently return the same integer, provided no information
used in equals comparisons on the object is modified.
This integer need not remain consistent from one execution of an
application to another execution of the same application.
- If two objects are equal according to the equals(Object)
method, then calling the hashCode method on each of
the two objects must produce the same integer result.
- It is not required that if two objects are unequal
according to the equals(Object) method, then calling the
hashCode method on each of the two objects must produce
distinct integer results. However, the programmer should be aware
that producing distinct integer results for unequal objects may
improve the performance of hashtables.
From this contract you can draw a conclusion that 'hashCode()' implementation should use only immutable fields of the object. Why? Lets create user domain object:
public class User {
private Long id;
private String name;
public User(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean equals(Object obj) {
return (this == obj) ||
(obj instanceof User && equals((User) obj));
}
public boolean equals(User that) {
EqualsBuilder builder = new EqualsBuilder()
.append(id, that.id)
.append(name, that.name);
return builder.isEquals();
}
public int hashCode() {
HashCodeBuilder builder = new HashCodeBuilder()
.append(id)
.append(name);
return builder.toHashCode();
}
}
I have used commons-lang to generate 'equals()' and 'hashCode()' but it doesn't matter. Now lets test if our 'hashCode()' is correct by running JUnit test:
public class UserTest {
@Test
public void testMutableName() {
Setusers = new HashSet ();
User user = new User("user");
user.setId(5L);
users.add(user);
user.setName("user2");
Assert.assertTrue(users.contains(user));
}
}
This test will fail because hash code of the user object was changed while user object itself was saved in the collection that uses it to save objects more efficiently.
Try to include in the 'hashCode()' only immutable fields, because you can have hidden issues not only with your own code but also with frameworks like Hibernate. If you don't have immutable fields, then be very careful and take described issues into account (recreate objects instead of changing them, don't use long live collections, return constant from 'hashCode()' or 'ID' field value). I hope this article will save you time for debugging. Develop with pleasure!
No comments:
Post a Comment