All ideas I have taken from the book Effective Java Joshua Bloch.
0. Overriding equal method
Usually overriding equals method is not recommended.
When an object x is being compared with another object y, equal method should maintain the following invariant
a. Reflexive - x.equals(x) should always be true
b. Symmetric: if x.equals(y) is true so should be y.equals(x)
c. Transitive: if x.equals(y) and y.equals(z) are true so should be x.equals(z)
d. Consistent: if x.equals(y) true, then it should remain true for any number of equals method calls given the criteria that determines object x and y's equality did not change.
f. Null is not an object: x.equals(null) should always be false
Consequence of violating the property:
If the above constraints are not met, then usage of an object collection might produce erroneous result.
list = new List()
list.add(x)
Reflexive property is not met: x.equals(x) returns false. list.contain(x) will return false. which is untrue.
Symmetric property is not met: x.equals(y) is true while y.equals(x) is false . if we add list.add(y) and check list.contains(x) it will return false.
General guidelines
a. If it is the reference of the same object, equal should return true. Check this with == operator.
b. Check if the object is of same Class through instanceOf operator. This takes care of null check.
null instanceOf ClassType equals to false.
c. Compare fields first that are more likely to change.
d. Make sure the constraints are not violated.
e. Override hashCode method if equals is overridden. Otherwise map data structures will produce incorrect results as similar to the examples provided for lists cases above.
1. Override hashCode() when equals() is overridden
To insert and object to a hash-based collection (hash map, hash set), the collections at first calculates hashCode of the object, then based on hash code it stores the object to one of buckets. This means equal objects must return equal hashCodes, otherwise collections would end up looking into a wrong bucket where the desired object was not added. By overriding hashCode(), we can guarantee the constraint holds.
If fields that are used to compare object equality are not changed, subsequent calls to hashCode() should produce the same value.
An example on writing a good hashCode()
class TestClass{
field x; //used in object equality check
field y; //used in object equality check
field z;
int a; //used in object equality check
int b; //used in object equality check
hashCode(){
base = 37; //this chosen as it is a odd prime
result = 17;
result = result * base + x.hashCode();
result = result * base + y.hashCode();
result = result * base + a;
result = result * base + b;
return result;
}
}
To do not be tempted to exclude a field's hashcode. For example, to getHashCode of a String only 16 characters in the beginning is taken then most of the urls will produce the same hashcode which will make a hashmap perform like a linked list.
0. Overriding equal method
Usually overriding equals method is not recommended.
When an object x is being compared with another object y, equal method should maintain the following invariant
a. Reflexive - x.equals(x) should always be true
b. Symmetric: if x.equals(y) is true so should be y.equals(x)
c. Transitive: if x.equals(y) and y.equals(z) are true so should be x.equals(z)
d. Consistent: if x.equals(y) true, then it should remain true for any number of equals method calls given the criteria that determines object x and y's equality did not change.
f. Null is not an object: x.equals(null) should always be false
Consequence of violating the property:
If the above constraints are not met, then usage of an object collection might produce erroneous result.
list = new List()
list.add(x)
Reflexive property is not met: x.equals(x) returns false. list.contain(x) will return false. which is untrue.
Symmetric property is not met: x.equals(y) is true while y.equals(x) is false . if we add list.add(y) and check list.contains(x) it will return false.
General guidelines
a. If it is the reference of the same object, equal should return true. Check this with == operator.
b. Check if the object is of same Class through instanceOf operator. This takes care of null check.
null instanceOf ClassType equals to false.
c. Compare fields first that are more likely to change.
d. Make sure the constraints are not violated.
e. Override hashCode method if equals is overridden. Otherwise map data structures will produce incorrect results as similar to the examples provided for lists cases above.
1. Override hashCode() when equals() is overridden
To insert and object to a hash-based collection (hash map, hash set), the collections at first calculates hashCode of the object, then based on hash code it stores the object to one of buckets. This means equal objects must return equal hashCodes, otherwise collections would end up looking into a wrong bucket where the desired object was not added. By overriding hashCode(), we can guarantee the constraint holds.
If fields that are used to compare object equality are not changed, subsequent calls to hashCode() should produce the same value.
An example on writing a good hashCode()
class TestClass{
field x; //used in object equality check
field y; //used in object equality check
field z;
int a; //used in object equality check
int b; //used in object equality check
hashCode(){
base = 37; //this chosen as it is a odd prime
result = 17;
result = result * base + x.hashCode();
result = result * base + y.hashCode();
result = result * base + a;
result = result * base + b;
return result;
}
}
To do not be tempted to exclude a field's hashcode. For example, to getHashCode of a String only 16 characters in the beginning is taken then most of the urls will produce the same hashcode which will make a hashmap perform like a linked list.
No comments:
Post a Comment