同时提醒一句如果把这个对象作为HashMap、HashTable或者HashSet的Key时,override equals()时一定要override hashcode(),因为hashcode协定中规定,相等的对象一定有相同的散列码。高质量hashcode写法:
1. 把某个非零常数值,比如说1 7,保存在一个叫result的int类型的变量中。
2. 对于对象中每一个关键域f(指equals方法中考虑的每一个域),完成以下步骤:
a. 为该域计算int类型的散列码c:
i. 如果该域是boolean类型,则计算( f ? 0 : 1 )
ii. 如果该域是byte、char、short或者int类型,则计算(int) f。
iii. 如果该域是long类型,则计算(int)(f^(f >>>32))
i v. 如果该域是float类型,则计算Float.floatToIntBits(f)。
v. 如果该域是double类型,则计算Double.doulbeToLongBits(f)得到一个long类型的值,然后按照步骤2.a.iii,对该long型值计算散列值。
vi. 如果该域是一个对象引用,并且该类的equals方法通过递归调用equals的方式来比较这个域,则同样对这个域递归调用hashCode。如果要求一个更为复杂的比较,则为这个域计算一个“规范表示( canonical representation)”,然后针对这个范式表示调用hashCode。如果这个域的值为null ,则返回0(或者其他某个常数,但习惯上使用0)。
vii. 如果该域是一个数组,则把每一个元素当做单独的域来处理。也就是说,递归地应用上述规则,对每个重要的元素计算一个散列码,然后根据步骤2.b中的做法把这些散列值组合起来。
摘自《Effective Java》
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.
使用 == 操作符检查实参是否为指向这个对象的一个引用。如果是的话,则返回true。这只不过是一种性能优化,如果比较操作有可能非常耗时的话,这样做是值得的。
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.
使用instanceof操作符检查“实参是否为正确的类型”。如果不是的话,则返回false。通常,这里“正确的类型”是指equals方法所在的那个类。有些情况下,是指该类所实现的某个接口。如果一个类实现的一个接口改进了equals约定,允许在实现了该接口的类之间进行比较,那么使用这个接口作为正确的类型。集合接口(collection interface)Set、List、Map和Map.Entry具有这样的特点。
3. Cast the argument to the correct type. Because this cast was preceded by an
instanceof test, it is guaranteed to succeed.
把实参转换到正确的类型。因为前面已经有了instanceof测试,所以这个转换可以确保成功。
4. For each “significant” field in the class, check if that field of the argument
matches the corresponding field of this object. If all these tests succeed, return
true; otherwise, return false. If the type in step 2 is an interface, you
must access the argument’s fields via interface methods; if the type is a class,
you may be able to access the fields directly, depending on their accessibility.
对于该类中每一个“关键(significant)”域,检查实参中的域与当前对象中对应的域值是否匹配。如果所有的测试都成功,则返回true;否则返回false。如果第2步中的类型是一个接口,那么你必须通过接口的方法,访问实参中的关键域;如果该类型是一个类,那么你也许能够直接访问实参中的关键域,这要取决于它们的可访问性。