Recently we discussed
equals()
and
hashCode()
implementations. A proper implementation is not trivial, as "father" Bloch
showed us years ago. Back in 2004 I wrote a plugin for Eclipse 2 to generate these methods. (Unfortunately I never managed to publish it. I know I am weak ;-) My home grown solution would produce something like
public int hashCode() {
long bits;
int result = 17;
result = 37 * result + (aBoolean ? 1231 : 1237);
result = 37 * result + (int)
((bits = Double.doubleToLongBits(aDouble)) ^ (bits >> 32));
result = 37 * result + (int) (aLong ^ (aLong >> 32));
result = 37 * result + anInt;
if (anObject != null) {
result = 37 * result + anObject.hashCode();
}
if (anArray != null) {
result = 37 * result + anArray.hashCode();
}
return result;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
else if (obj == null || getClass() != obj.getClass()) {
return false;
}
final Homegrown o = (Homegrown) obj;
return (aBoolean == o.aBoolean &&
aDouble == o.aDouble &&
aLong == o.aLong &&
anInt == o.anInt &&
(anObject == o.anObject ||
(anObject != null && anObject.equals(o.anObject))) &&
(anArray == o.anArray ||
(anArray != null && anArray.equals(o.anArray))));
}
I know, I know the implementation for arrays is most likely
not what you want. (Did I say that I am weak? :-) Since Java 5 one could use the
java.util.Arrays
class to fix it. Nevertheless, it served me well for some years. There are several other plugins for Eclipse, and
Scott McMaster wrote about in 2006. Since version 3.3 (Europa) Eclipse can finally do it on its own:
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (aBoolean ? 1231 : 1237);
long temp;
temp = Double.doubleToLongBits(aDouble);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + (int) (aLong ^ (aLong >>> 32));
result = prime * result + anInt;
result = prime * result +
((anObject == null) ? 0 : anObject.hashCode());
result = prime * result + Arrays.hashCode(anArray);
return result;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Eclipse33Java5 other = (Eclipse33Java5) obj;
if (aBoolean != other.aBoolean) {
return false;
}
if (Double.doubleToLongBits(aDouble) !=
Double.doubleToLongBits(other.aDouble)) {
return false;
}
if (aLong != other.aLong) {
return false;
}
if (anInt != other.anInt) {
return false;
}
if (anObject == null) {
if (other.anObject != null) {
return false;
}
}
else if (!anObject.equals(other.anObject)) {
return false;
}
if (!Arrays.equals(anArray, other.anArray)) {
return false;
}
return true;
}
Using the ternary operator the
hashCode
method gets quite compact, but
equals
is a bit too verbose for my liking. IntelliJ IDEA could always generate these methods. IDEA 7.0 creates something like
public int hashCode() {
int result;
long temp;
result = (aBoolean ? 1 : 0);
temp = aDouble != +0.0d ? Double.doubleToLongBits(aDouble) : 0L;
result = 31 * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + (int) (aLong ^ (aLong >>> 32));
result = 31 * result + anInt;
result = 31 * result +
(anObject != null ? anObject.hashCode() : 0);
result = 31 * result +
(anArray != null ? Arrays.hashCode(anArray) : 0);
return result;
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Idea70Java5 original = (Idea70Java5) o;
if (aBoolean != original.aBoolean) {
return false;
}
if (Double.compare(original.aDouble, aDouble) != 0) {
return false;
}
if (aLong != original.aLong) {
return false;
}
if (anInt != original.anInt) {
return false;
}
if (anObject != null ? !anObject.equals(original.anObject) :
original.anObject != null) {
return false;
}
// Probably incorrect - comparing Object[] with Arrays.equals
if (!Arrays.equals(anArray, original.anArray)) {
return false;
}
return true;
}
Typical IDEA, with a little fix for
+0.0/-0.0
and some warning concerning
Arrays.equals
, but else totally the same. In fact, all these implementations suck (including my own, which sucks most). All these
result = prime * result ...
and
if ... return false;
are definitely not
DRY. I always favour
Apache Commons Lang builders. A hand-coded solution using them would look like
public int hashCode() {
return new HashCodeBuilder().
append(aBoolean).
append(aDouble).
append(aLong).
append(anInt).
append(anObject).toHashCode();
}
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
ApacheCommons o = (ApacheCommons) other;
return new EqualsBuilder().
append(aBoolean, o.aBoolean).
append(aDouble, o.aDouble).
append(aLong, o.aLong).
append(anInt, o.anInt).
append(anObject, o.anObject).
append(anArray, o.anArray).isEquals();
}
Well, that's much shorter, isn't it.