Consider the example:
public class StringHelper {
private String inputString;
public StringHelper(String string) {
inputString=string;
}
@Override
public int hashCode() {
return inputString.length();
}
public static void main(String[] args) {
StringHelper helperObj = new StringHelper("string");
StringHelper helperObj1 = new StringHelper("string");
if(helperObj.hashCode() == helperObj1.hashCode()){
System.out.println("HashCode are equal");
}
if(helperObj.equals(helperObj1)){
System.out.println("Objects are equal");
}else{
System.out.println("Objects are not equal");
}
}
public String getInputString() {
return inputString;
}
// Output:
HashCode are equal
Objects are not equal
We can see that even though the StringHelper object contains the same value the equals method has returned false but the hashcode method has return true value.
To prevent this inconsistency, we should make sure that we override both methods such that the contract between both methods doesn't fail.
Steps that need to be taken into consideration while implementing equals method.
1. Use the == operator to check if the argument is a reference to this object. If so, return true. This is just a performance optimization, but one that is worth doing if the comparison is potentially expensive.
2. Use the instanceof operator to check if the argument has the correct type.
If not, return false. Typically, the correct type is the class in which the method occurs. Occasionally, it is some interface implemented by this class. Use an interface if the class implements an interface that refines the equals contract to permit comparisons across classes that implement the interface. Collection interfaces such as Set, List, Map, and Map.Entry have this property.
3. Cast the argument to the correct type. Because this cast was preceded by an instanceof test, it is guaranteed to succeed.
4. For each significant field in the class, checks if that field of the argument matches the corresponding field of this object.If all these tests succeed, return true; otherwise, return false
5. When you are finished writing your equals method, ask yourself three questions: Is it symmetric? Is it transitive? Is it consistent?
The correct implementation if equals method for the StringHelper class could be:
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final StringHelper other = (StringHelper) obj;
if (inputString == null) {
if (other.inputString != null)
return false;
} else if (!inputString.equals(other.inputString))
return false;
return true;
}