在equals()中使用缓存的hashCode()值

Kan*_*mar 1 java hash equals

对于不可变类String; String :: hashCode计算只会在该对象的生命周期中发生一次.所以hashCode()第一次打电话后总是回来private int hash.计算时不会浪费CPU.

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {    // **h != 0 in second time**
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}
Run Code Online (Sandbox Code Playgroud)

我们知道hashcode和equals之间的契约

equal objects must produce the same hash code

所以我相信下面的代码将改善字符串equals()的性能.这在hashmap中可能是多余的,因为hashmap已经基于哈希码获得了桶,但是这在BIG List搜索上具有良好的性能改进.

//Does the below will improve equals performance on BIG LIST?
if (this.hashCode() != anObject.hashCode()) {
        return false;
}
Run Code Online (Sandbox Code Playgroud)

请在下面的api中评论您的想法.

public boolean equals(Object anObject) {
if (this == anObject) {
    return true;
}

if (this.hashCode() != anObject.hashCode()) {
    return false;
}

if (anObject instanceof String) {
    String anotherString = (String)anObject;
    int n = count;
    if (n == anotherString.count) {
    char v1[] = value;
    char v2[] = anotherString.value;
    int i = offset;
    int j = anotherString.offset;
    while (n-- != 0) {
        if (v1[i++] != v2[j++])
        return false;
    }
    return true;
    }
}
return false;
}
Run Code Online (Sandbox Code Playgroud)

UPDATE

正如'dasblinkenlight'所提到的,只有在第一次调用hashcode()时才需要一些cpu周期.

由于Java正在维护String Pool; 如果应用程序需要大的String多次时间比较而不是散列; 然后我们可以去下面的效用方法.

public boolean StringCompare (String one, String two) {

     if (one == two) {
         return true;
     }

     if (one.hashCode() != two.hashCode()) {
        return false;
     }


    int n = one.count;
    if (n == two.count) {
    char v1[] = one.value;
    char v2[] = two.value;
    int i = one.offset;
    int j = two.offset;
    while (n-- != 0) {
        if (v1[i++] != v2[j++])
        return false;
    }
    return true;
Run Code Online (Sandbox Code Playgroud)

}

das*_*ght 8

当你知道比较在大多数情况下会失败时,在你自己的代码中进行这样的检查以保存相等检查没有错,但是将它放入通用代码中有可能降低整体性能.你的系统有两个原因:

  • 首次计算哈希码需要一些CPU周期; 当equals在哈希容器的上下文之外调用方法时,计算哈希代码所需的CPU周期将被浪费
  • Strings用作哈希容器中的键时,容器在继续进行相等性检查之前建立哈希码的相等性,因此equals()方法内的哈希码的比较变得多余.


Igo*_*gor 5

Java非常擅长优化,您不需要对其进行微优化.您应该编写可维护且可读的代码,并在查看可能导致问题的源(以及经过多次性能测试之后)后查看性能.编写模糊或难以阅读的代码很可能会导致将来当您或其他人无法识别该方法的编写方式时会出现错误.

您是否发现自己.equals()是表现的瓶颈?如果没有,我会说坚持使用更具可读性且不太可能在将来引入错误的代码.您的情况下的性能差异很可能是微不足道的,但您可以运行测试来比较这两个实现.