Java String真的是不可变的吗?

时间:2010-10-25 03:25:02

标签: java

在String源中,只有在方法public int hashCode()被调用至少一次时,才会设置哈希码值(private int hashCode)。这意味着一个不同的状态。但是hashCode是否会在以下示例中设置:

String s = "ABC"; ? 

String s = "ABC"; 
s.hashCode();

帮助进行后续的比较表现?

6 个答案:

答案 0 :(得分:12)

不可变意味着,从外部来看,不能改变对象的价值。

如果正在缓存hashCode,则在第一次hashCode调用后,对象的内部状态可能会有所不同。但是这个调用是只读的,你不能改变对象的外观世界的价值。

换句话说,它仍然是相同的字符串。

答案 1 :(得分:4)

技术上字符串已更改。第一次调用hashCode()时会更改某些内部字段。

但是对于所有实际原因,字符串是不可变的。由于调用hashCode(),哈希码的值不会改变,直到第一次调用时才会计算。对于字符串的任何使用者,字符串是不可变的。这才是最重要的。

答案 2 :(得分:3)

正如Robert Harvey和Greg所说,出于所有实际目的, String对象是不可变的(可能可以通过反射更改内容,但这是一个黑客攻击)。

在构建之后立即致电hashCode()可能有助于理论上的表现。但是,出于所有实际目的,这是过早优化

答案 3 :(得分:2)

  

但是hashCode会在以下示例中设置吗?

没有

  

[调用hashCode]会帮助进行后续的比较性能吗?

假设您的意思是后续拨打String.equals(Object),则答案为“否”。 equals方法不使用String的hash值,无论之前是否已计算过。

如果您指的是对String.hashCode()的来电,答案是“可能不是”。至多你会得到一次性计算,以便尽早发生。 hashCode方法仍然需要测试每次调用时hash是否为零。

修改

我认为很明显,不同的JVM供应商以不同的方式实现String.equals。例如,@ Alex引用的IBM版本使用缓存的哈希码,但Sun的JDK 1.6中的版本不使用。

由此我们得出结论,任何为了“优化”String.hashCode()而调用String.equals的尝试都会产生依赖于JVM的结果。此外,对于@Alex正在使用的特定IBM JVM,看起来可能是有益的...前提是您已经为两个字符串完成了它。

但我仍然认为这是一个坏主意......除非你从分析中得到明确的证据String.equals()是一个重要的瓶颈。

答案 4 :(得分:0)

  1. 没有。没有人打电话给它,所以没有打电话。

  2. 没有。怎样才能把一个方法称为额外的时间让事情变得更快?

答案 5 :(得分:-1)

这是实际的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;
}

所以:

  1. 字符串是不可变的,你无法改变它的价值。您只能创建一个新的字符串。
  2. 首次使用String.hashCode()时计算字符串哈希码。以后的调用返回预先计算的值:
  3. 是的,它会更快。如果你调用.hashCode(),那么后续的比较会在一次计算hachcode的一小段时间内更快。问题是这是否是实质性的。做自己的基准。