【发布时间】:2010-10-25 03:25:02
【问题描述】:
在字符串源中,看起来哈希码值(私有 int hashCode)仅在方法 public int hashCode() 至少被调用一次时才被设置。这意味着不同的状态。但是下面的例子中会设置hashCode吗:
String s = "ABC"; ?
会
String s = "ABC";
s.hashCode();
对后续比较性能有帮助吗?
【问题讨论】:
标签: java
在字符串源中,看起来哈希码值(私有 int hashCode)仅在方法 public int hashCode() 至少被调用一次时才被设置。这意味着不同的状态。但是下面的例子中会设置hashCode吗:
String s = "ABC"; ?
会
String s = "ABC";
s.hashCode();
对后续比较性能有帮助吗?
【问题讨论】:
标签: java
不可变意味着,从外部角度来看,对象的值不能改变。
如果hashCode被缓存,对象的内部状态在第一次hashCode调用后可能会有所不同。但该调用是只读的,您无法更改对象在外界看来的值。
换句话说,它仍然是同一个字符串。
【讨论】:
hash 值的缓存是经典的记忆。
技术上字符串已更改。第一次调用 hashCode() 时,某些内部字段已更改。
但出于所有实际原因,字符串是不可变的。哈希码的值不会因为调用hashCode() 而改变,它只是在第一次调用之前不会计算。对于字符串的任何使用者,该字符串是不可变的。这才是最重要的。
【讨论】:
正如 Robert Harvey 和 Greg 所说,出于所有实际目的,String 对象是不可变的(可以通过反射来更改内容,但这是一种 hack)。
在构造完成后立即调用hashCode()可能有助于提高理论性能。但是,出于所有实际目的,这是过早的优化。
【讨论】:
但是下面的例子中会设置hashCode吗?
没有。
[调用 hashCode] 对后续比较性能有帮助吗?
假设您的意思是后续调用String.equals(Object),答案是“否”。 equals 方法不使用 String 的 hash 值,无论之前是否计算过。
如果您指的是对String.hashCode() 的调用,答案是“可能不是”。最多你会得到一个一次性的计算,而不是迟早发生。 hashCode 方法仍然需要在每次调用时测试 hash 是否为零。
编辑
我认为很明显不同的 JVM 供应商实现 String.equals 的方式不同。例如,@Alex 引用的 IBM 版本使用了缓存的 hashcode,但 Sun 的 JDK 1.6 中的版本没有。
由此我们得出结论,任何调用String.hashCode() 以“优化”String.equals 的尝试都会产生依赖于JVM 的结果。此外,对于 @Alex 正在使用的特定 IBM JVM,它看起来可能是有益的......前提是您已经为两个字符串都做了。
但我仍然认为这是一个坏主意......除非你从分析中得到明确的证据表明String.equals() 是一个重要的瓶颈。
【讨论】:
没有。没有人调用它,所以它没有被调用。
没有。多调用一个方法怎么会更快?
【讨论】:
这是实际的 String.hashCode() 实现:
public int hashCode() {
int h = hash; // hash is a field in String
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
所以:
【讨论】: