必须谨记:对于每一个类,重写equals
方法时,必须重写hashCode
方法。如果没有遵照此规定,则在所有基于hash
计算的类中(如:HashMap
、HashSet
和HashTable
)都会出问题。
hashCode
约定
Object
规范中有这样的约定:
- 在程序相同执行过程中多次调用同个对象,哈希值必须返回相同。但不是相同调用过程则不必相同;
- 如果两个对象调用equals()方法相同,则hashCode()方法返回值必须相同;
- 如果两个对象调用equals()方法不相同,并不需要两个对象的哈希值不相同。但是开发者必须意识到,不同的对象产生不同的哈希值可以提高像HashTable这样类的性能
重写hashCode
方法
若需要重写hashCode
方法,可以参照如下步骤:
1. 取个非0的常量值,赋值给result
。譬如,result=17
;
2. 对类中每一个关键属性(equals
方法中用到的属性)f
,作如下处理
1). 计算属性f
的哈希值,赋值给c
a. `f`为`boolean`类型,`c = f ? 1 : 0`
b. `f`为`byte`、`char`、`short`、`int`类型,`c = (int)f`
c. `f`为`long`类型,`c = (int)(f ^ (f >>> 32))`
d. `f`为`float`类型,`c = Float.floatToIntBits(f)`
e. `f`为`double`类型,首先`temp = Double.doubleToLongBits(f)`,之后按照2.1).c步骤来计算`c = (int)(temp ^ (temp >>> 32))`
f. `f`为对象引用,并且`equals`方法是通过迭代`f`的属性进行判断的,则`hashCode`方法也必须迭代计算`f`中的`hashCode`值。若需要更复杂的计算,则为此属性计算个范式,然后针对这个范式调用`hashCode`。如果属性为`null`,一般返回0
g. `f`为数组,则需将每一个元素单独按2.1).(a-f)步骤处理,然后按照2.2)将哈希值组合起来。若数组中每个元素都很重要,可以利用`Arrays.hashCode`方法计算
2). 将2.1)中计算的`c`合并到`result`中:`result = 31 * result + c`
3. 返回result