哈希码和排除字段
Hashcode and excluding fields
根据 Bloch 关于 hashCode 的建议:
You may ignore any field whose value can be computed from fields
included in the computation
我不明白这个。有人可以举一个真实的例子吗?我假设任何可以从其他字段生成字段的 class 出于性能原因只会将其存储在另一个变量中。但这与哈希码合约有什么关系?
class Example {
final int a;
final int b;
final int c;
Example(int a, int b) { this.a = a; this.b = b; this.c = a + b; }
}
在此处的 hashCode
计算中包含 c
没有任何意义:a
和 b
相等的任何实例也将具有 c
s 相等。
Objects.hash(this.a, this.b, this.c) == Objects.hash(that.a, that.b, that.c)
<=>
Objects.hash(this.a, this.b) == Objects.hash(that.a, that.b)
因此,您所做的只是 "perturbing" 通过包含 c
哈希码,即使其成为不同的值,但不是以有意义的方式。
一个实际的例子在String
中:String
有一个字段,hash
,存储哈希码的值,避免重复计算(source):
public int hashCode() {
int h = hash; // <-- hash is a member variable.
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
也许很明显,这不能算在哈希码计算中!但是可以从class.
中的其他字段导出
考虑一个 class 你有更多字段
class MyClass {
String name;
String surname;
String fullName;
}
在这个class中,对于哈希码的生成,唯一有意义的字段是name
和surname
。其余字段fullName
由其他人生成,可以忽略。
But what does this have to do with the hashcode contract?
它不属于 hashcode()
合同的一部分。您应该将其视为以有效方式实施它的良好做法(因为它省去了一些无用的计算)。
事实上,hashCode()
的良好实现应该依赖于与 equals()
方法使用的字段相同的字段。
如果您有一个包含 3 个字段的 class,例如 Addition
:
class Addition {
private float operandOne;
private float operandTwo;
private float result;
}
您不需要在 equals()
方法中使用 result
因为 result
在某种程度上是冗余信息,您不需要它来识别Addition
实例的独特方式。
您知道如果一个 Addition
实例中的 operandOne
和 operandTwo
与另一个 Addition
实例中的 operandOne
和 operandTwo
匹配,就足够了认为他们是平等的。
在hashcode()
方法中也是一样。
根据 Bloch 关于 hashCode 的建议:
You may ignore any field whose value can be computed from fields included in the computation
我不明白这个。有人可以举一个真实的例子吗?我假设任何可以从其他字段生成字段的 class 出于性能原因只会将其存储在另一个变量中。但这与哈希码合约有什么关系?
class Example {
final int a;
final int b;
final int c;
Example(int a, int b) { this.a = a; this.b = b; this.c = a + b; }
}
在此处的 hashCode
计算中包含 c
没有任何意义:a
和 b
相等的任何实例也将具有 c
s 相等。
Objects.hash(this.a, this.b, this.c) == Objects.hash(that.a, that.b, that.c)
<=>
Objects.hash(this.a, this.b) == Objects.hash(that.a, that.b)
因此,您所做的只是 "perturbing" 通过包含 c
哈希码,即使其成为不同的值,但不是以有意义的方式。
一个实际的例子在String
中:String
有一个字段,hash
,存储哈希码的值,避免重复计算(source):
public int hashCode() {
int h = hash; // <-- hash is a member variable.
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
也许很明显,这不能算在哈希码计算中!但是可以从class.
中的其他字段导出考虑一个 class 你有更多字段
class MyClass {
String name;
String surname;
String fullName;
}
在这个class中,对于哈希码的生成,唯一有意义的字段是name
和surname
。其余字段fullName
由其他人生成,可以忽略。
But what does this have to do with the hashcode contract?
它不属于 hashcode()
合同的一部分。您应该将其视为以有效方式实施它的良好做法(因为它省去了一些无用的计算)。
事实上,hashCode()
的良好实现应该依赖于与 equals()
方法使用的字段相同的字段。
如果您有一个包含 3 个字段的 class,例如 Addition
:
class Addition {
private float operandOne;
private float operandTwo;
private float result;
}
您不需要在 equals()
方法中使用 result
因为 result
在某种程度上是冗余信息,您不需要它来识别Addition
实例的独特方式。
您知道如果一个 Addition
实例中的 operandOne
和 operandTwo
与另一个 Addition
实例中的 operandOne
和 operandTwo
匹配,就足够了认为他们是平等的。
在hashcode()
方法中也是一样。