Java 编译器通常会预先计算 Final 字段的哈希码吗?

问题描述 投票:0回答:3

我有一个

HashMap
密集型 Java 程序,其中几个类具有根据
final
字段计算的哈希码。例如:

public class Foo {
    private final int bar;
    private final String zot;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + bar;
        result = prime * result + zot.hashCode();
        return result;
    }
}

编译器可能会观察到哈希码在对象初始化后无法更改,并将其预先计算到附加的

private final
字段中。当前的 Java 编译器是否会执行此操作(如 Oracle JDK 7 中的编译器)?我可以反汇编
.class
文件,但是 JIT 也可能在运行时进行这种优化,但我不会在那里看到它。不管怎样,我对除此之外的其他情况感兴趣,因此找到一种通用方法来识别编译器自动执行的任何优化将是很棒的。

java optimization
3个回答
6
投票

当前的 Java 编译器是否会执行此操作(如 Oracle JDK 7 中的编译器)?

javac
几乎没有进行任何优化。

我可以反汇编 .class 文件,

您可能不喜欢所看到的优化结果。 ;)

但是 JIT 也可能在运行时进行这种优化,但我不会在那里看到它。

如果 JIT 确实对此进行了优化,您将看不到它,而且事实上它并没有这样做。 这就是 String 在运行时显式地在代码中缓存其 hashCode() 的原因。


2
投票

不,编译器不会这样做。然而,将哈希码自己存储在一个字段中并引用它并不难,而不是一直重新计算:

private int hash = -1;

public int hashCode() {
    if (hash == -1) {
        // compute hash, assign it to the hash variable, and return it
    } else {
        return hash;
    }
}

这种方法实际上是由

String
类采用的,如果你检查它的 source 就可以看到:

121  /** Cache the hash code for the string */
122  private int hash; // Default to 0

1
投票

编译器可以对任何合适的方法执行此操作,而不仅仅是

hashCode(),
,但事实并非如此。你可以通过
javap -p
亲眼看看是否有添加的字段,还可以通过
javap -c
看到字节码。

但是您发布的方法不适合。运行时

String.hashCode()
的实现可能与编译器可用的实现不同。编译器不能假设它不是。

© www.soinside.com 2019 - 2024. All rights reserved.