update 11. 重写 equals 方法时同时也要重写 hashcode 方法

This commit is contained in:
sjsdfg 2019-04-03 20:28:50 +08:00
parent f2e2a16d79
commit d4acbf6209

View File

@ -12,7 +12,6 @@
```java
Map<PhoneNumber, String> m = new HashMap<>();
m.put(new PhoneNumber(707, 867, 5309), "Jenny");
```
@ -23,7 +22,6 @@ m.put(new PhoneNumber(707, 867, 5309), "Jenny");
```java
// The worst possible legal hashCode implementation - never use!
@Override public int hashCode() { return 42; }
```
@ -37,7 +35,7 @@ m.put(new PhoneNumber(707, 867, 5309), "Jenny");
&nbsp;&nbsp;&nbsp;&nbsp;-- i. 如果这个属性是基本类型的,使用 `Type.hashCode(f)` 方法计算,其中 `Type` 类是对应属性 `f` 基本类型的包装类。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;-- ii. 如果该属性是一个对象引用,并且该类的 equals 方法通过递归调用 equals 来比较该属性,并递归地调用 hashCode 方法。 如果需要更复杂的比较则计算此字段的“范式“canonical representation并在范式上调用 hashCode。 如果该字段的值为空,则使用 0也可以使用其他常数但通常来使用 0 表示)。<br/>
&nbsp;&nbsp;&nbsp;&nbsp; -- iii. 如果属性 `f` 是一个数组,把它看作每个重要的元素都是一个独立的属性。 也就是说,通过递归地应用这些规则计算每个重要元素的哈希码,并且将每个步骤 2.b 的值合并。 如果数组没有重要的元素,则使用一个常量,最好不要为 0。如果所有元素都很重要则使用 `Arrays.hashCode` 方法。<br/>
&nbsp;&nbsp;&nbsp;&nbsp; -- iii. 如果属性 `f` 是一个数组,把它看作每个重要的元素都是一个独立的属性。 也就是说,通过递归地应用这些规则计算每个重要元素的哈希码,并且将每个步骤 2.b 的值合并。 如果数组没有重要的元素,则使用一个常量,最好不要为 0。如果所有元素都很重要则使用 `Arrays.hashCode` 方法。<br/>
b. 将步骤 2.a 中属性 c 计算出的哈希码合并为如下结果:`result = 31 * result + c;`
@ -53,18 +51,12 @@ m.put(new PhoneNumber(707, 867, 5309), "Jenny");
```java
// Typical hashCode method
@Override
public int hashCode() {
int result = Short.hashCode(areaCode);
result = 31 * result + Short.hashCode(prefix);
result = 31 * result + Short.hashCode(lineNum);
return result;
}
```
@ -77,12 +69,9 @@ public int hashCode() {
```java
// One-line hashCode method - mediocre performance
@Override
public int hashCode() {
return Objects.hash(lineNum, prefix, areaCode);
}
```
@ -90,28 +79,18 @@ public int hashCode() {
```java
// hashCode method with lazily initialized cached hash code
private int hashCode; // Automatically initialized to 0
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = Short.hashCode(areaCode);
result = 31 * result + Short.hashCode(prefix);
result = 31 * result + Short.hashCode(lineNum);
hashCode = result;
}
return result;
}
```
@ -122,7 +101,7 @@ public int hashCode() {
  **不要为 hashCode 返回的值提供详细的规范,因此客户端不能合理地依赖它; 你可以改变它的灵活性。** Java 类库中的许多类(例如 String 和 Integer都将 hashCode 方法返回的确切值指定为实例值的函数。 这不是一个好主意,而是一个我们不得不忍受的错误:它妨碍了在未来版本中改进哈希函数的能力。 如果未指定细节并在散列函数中发现缺陷,或者发现了更好的哈希函数,则可以在后续版本中对其进行更改。
  总之,每次重写 equals 方法时都必须重写 hashCode 方法,否则程序将无法正常运行。你的 hashCode 方法必须遵从 Object 类指定的常规约定,并且必须执行合理的工作,将不相等的哈希码分配给不相等的实例。如果使用第 51 页的配方,这很容易实现。如条目 10 所述AutoValue 框架为手动编写 equals 和 hashCode 方法提供了一个很好的选择IDE 也提供了一些这样的功能。
[1]: http://com.google.common.hash.hashing/
[1]: http://com.google.common.hash.hashing/