Commons Lang
EqualsBuilder
and
HashCodeBuilder
provide methods to automate both the equals( )
and
hashCode( )
. Example 1-2 briefly
demonstrates these two builders using the
PoliticalCandidate
bean from the previous two
recipes.
Example 1-2. Automating hashCode( ) and equals( )
import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.EqualsBuilder; public class PoliticalCandidate { // Member variables - omitted for brevity // Constructors - omitted for brevity // get/set methods - omitted for brevity // A hashCode which creates a hash from the two unique identifiers public int hashCode( ) { return new HashCodeBuilder(17, 37) .append(firstName) .append(lastName).toHashCode( ); } // An equals which compares two unique identifiers public boolean equals(Object o) { boolean equals = false; if ( o != null && PoliticalCandidate.class.isAssignableFrom(o) ) { PoliticalCandidate pc = (PoliticalCandidate) o; equals = (new EqualsBuilder( ) .append(firstName, ps.firstName) .append(lastName, ps.lastName)).isEquals( ); } return equals; } }
HashCodeBuilder
has a constructor that takes two
integer primitives. These primitives are used as an offset when
creating a hash code; both numbers should be odd, nonzero, and prime.
The HashCodeBuilder
in Example 1-2 is configured to use the
firstName
and the lastName
of
the PoliticalCandidate
object; therefore, two
PoliticalCandidate
objects with the same first and
last name will have identical hash codes. If a hash code depends on
every field in a class, you may use reflection to generate a hash
code:
public int hashCode( ) { return HashCodeBuilder.reflectionHashCode(this); }
Like ToStringBuilder
and
HashCodeBuilder
, the
EqualsBuilder
is also configured via an
append( )
method, which takes two arguments to
compare. EqualsBuilder
’s
append( )
method accepts all primitives, objects,
and arrays, and one advantage of EqualsBuilder
is
the ability to compare two arrays by simply passing them to
append( )
. When this happens,
EqualsBuilder
compares every element of an array:
int[] array1 = new int[] { 1, 3, 4, 2, 5, 3, 4, 5, 3, 4 }; int[] array2 = new int[] { 1, 3, 4, 2, 5, 3, 4, 5, 3, 4 }; int[] array3 = new int[] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; EqualsBuilder builder = new EqualsBuilder( ); builder.append( array1, array2 ); boolean firstTwoEqual = builder.isEquals( ); System.out.println( "Is array1 equal to array2? " + firstTwoEqual ); EqualsBuilder builder = new EqualsBuilder( ); builder.append( array2, array3 ); boolean lastTwoEqual = builder.isEquals( ); System.out.println( "Is array2 equal to array3? " + lastTwoEqual );
The EqualsBuilder
compares the contents of two
arrays, checking to see that the corresponding element is equal. The
following output is produced:
Is array1 equal to array2? true Is array2 equal to array3? false
If two classes are equal only if every field is equal, the
EqualsBuilder
can compare two objects using
reflection as in the following code:
public boolean equals(Object o) { return EqualsBuilder.reflectionEquals(this, o); }
Be careful when using reflection to automate hashCode()
and equals( )
, you may get more than
you bargained for. In Example 1-2, a candidate is
uniquely identified by first and last name; if this bean were mapped
to a table in a relational database, firstName
and
lastName
would be a composite key identifying each
unique row. A HashMap
or
HashSet
is similar to a database table in that the
identifier is defined by the fields used by hashCode()
and equals( )
; putting an equal object
with the same hash code into a HashMap
replaces
the previous entry. A poorly implemented hashCode( )
or equals( )
can have unintended
consequences when storing objects in such a data structure. In other
words, equals( )
and hashCode()
should be based off of the properties that uniquely
identify a class. This being the case, the equals()
function should return true if two
PoliticalCandidate
objects have
identical first
and
last names, and the hash code for two equal objects should be
identical. The hashCode( )
and equals()
in Example 1-2 are written to only take
into account the firstName
and
lastName
properties.
3.143.205.27