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

Java 在equals()中使用缓存的hashCode()值,java,hash,equals,Java,Hash,Equals,对于不可变的类字符串字符串::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;

对于不可变的类字符串<代码>字符串::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;
}
请在下面的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;
}
更新 正如“dasblinkenlight”所提到的,只有在第一次调用hashcode()API时才需要一些cpu周期

因为Java维护字符串池;若应用程序需要大字符串多次比较,而不是散列;然后我们可以使用下面的实用方法

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;

}

您的优化需要对实际上彼此相等的字符串对象做更多的工作,因为您仍然需要迭代它们以确保它们相等


契约要求equals对象生成相同的哈希代码。反之亦然,因为生成相同哈希代码的对象不一定相等(哈希冲突)。

您的优化将需要对实际上彼此相等的字符串对象进行更多的工作,因为您仍然需要迭代它们以确保它们相等


契约要求equals对象生成相同的哈希代码。反之亦然,因为产生相同哈希代码的对象不一定相等(哈希冲突)。

Java非常擅长优化,您不需要为此进行微优化。您应该编写可维护和可读的代码,并在查看了可能导致问题的源代码(以及许多性能测试之后)之后再查看性能。编写晦涩难懂或难以阅读的代码很可能会在将来导致错误,因为您或其他人无法识别方法为何以这种方式编写


您是否发现您的
.equals()
是性能的瓶颈?如果不是的话,我会说坚持使用可读性更好、将来不太可能引入bug的代码。您案例中的性能差异很可能可以忽略不计,但您可以运行测试来比较这两种实现。

Java非常擅长优化,您不需要对其进行微优化。您应该编写可维护和可读的代码,并在查看了可能导致问题的源代码(以及许多性能测试之后)之后再查看性能。编写晦涩难懂或难以阅读的代码很可能会在将来导致错误,因为您或其他人无法识别方法为何以这种方式编写


您是否发现您的
.equals()
是性能的瓶颈?如果不是的话,我会说坚持使用可读性更好、将来不太可能引入bug的代码。在您的情况下,性能差异很可能可以忽略不计,但您可以运行测试来比较这两种实现。

在您自己的代码中放入这样的检查,以便在您知道比较在大多数情况下都会失败的情况下保存相等性检查,这并没有错,但将其放入常规代码中可能会降低系统的整体性能,原因有两个:

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

当您知道比较大部分时间都会失败时,在您自己的代码中放入这样的检查来保存相等性检查并没有什么错,但将其放入常规代码中有可能会降低系统的整体性能,原因有两个:

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

评测应该是您的第一、第二和第三站,以查看一段代码是否比其他可能的重复代码快。请参见评测应该是您的第一、第二和第三站,以查看一段代码是否比其他可能的重复代码快。请参见,它将生成稍微多一些处理相等的字符串对象的工作,但在某些情况下,可能会节省大量关于长字符串对象的工作,这些对象仅在接近尾端时有所不同。太糟糕了,Java使用
string
实现正确内存屏障语义的唯一方法就是声明backing数组字段
final
,否则,通过让发现相等的字符串合并它们的备份存储,就可以优化长
equal
字符串之间的重复比较[请注意,如果旧的和新的备份存储包含相同的文本,那么如果某些线程……看到了交换,而其他线程没有看到交换,那就无关紧要了。这将为相等的字符串对象生成稍多的工作,但在某些情况下,可能会为仅在接近尾端时有所不同的长字符串对象节省大量工作。很遗憾,Java实现交换的唯一方法是对于
字符串
我认为适当的内存障碍语义是声明支持数组字段
final
,因为否则,可以通过让发现相等的字符串合并其支持存储来优化长
相等
字符串之间的重复比较[注意,如果是旧的
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;