If hashCode()
calculation uses immutable fields and equals()
uses all the fields would it be a problem when the class is used as a hash key? E.g.
import java.util.Objects;
public class Car {
protected final long vin;
protected String state;
protected String plateNumber;
public Car( long v, String s, String p ) {
vin = v; state = s; plateNumber = p;
}
public void move( String s, String p ) {
state = s; plateNumber = p;
}
public int hashCode() {
return (int)( vin % Integer.MAX_VALUE );
}
public boolean equals( Object other ) {
if (this == other) return true;
else if (!(other instanceof Car)) return false;
Car otherCar = (Car) other;
return vin == otherCar.vin
&& Objects.equals( state, otherCar.state )
&& Objects.equals( plateNumber, otherCar.plateNumber );
}
}
And move() is called on a car object after it is inserted into a hashset, possible via a reference kept elsewhere.
I am not after performance issues here. Only correctness.
I have read java hashCode contact, few answers on SO including this by venerable Jon Skeet and this from big blue. I feel that the last link gives the best explanation and imply that above code is correct.
Edit
Conclusion:
This class satisfy constraints placed on ‘equals()’ and ‘hashCode()’ in java. However it violates restrictions additional requirements placed on ‘equals()’ when used as keys in collections, hashed or not.
The additional requirement is that ‘equals()’ need to be consistent as long as the object is a key.
See the counter example by Louis Wasserman and the reference provided by Douglas below.
Few clarifications:
A) This class satisfy java object level constraints:
- ( carA == carB ) implies ( carA.hashCode() == carB.hashCode() )
- ( carA.hashCode() != carB.hashCode() ) implies ( carA != carB )
- equals() need to be reflexive, symmetric, transitive.
- hashCode() need to be consistent. i.e. Cannot change for an object during its lifetime.
- equals() need to be consistent as long as neither object is modified.
Note that the reverse of ‘1.’ and ‘2.’ are not necessary. And the class above satisfies all the conditions.
Also java docs mention "equals() … implements the most discriminating possible equivalence relation on objects", but not sure if that is compulsory.
B) As for performance, the increment in collision avoidance probability decrease with each successive member variable we combine. Usually few well chosen member variables is sufficient.