为什么 String 中的 equals 方法不使用哈希?

2022-09-01 00:33:59

类 String 中该方法的代码为equals

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    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;
}

我有一个问题 - 为什么这种方法不使用hashCode()?

据我所知,hashCode()可以快速比较两个字符串。

更新:我知道,两个不相等的字符串可以具有相同的哈希值。但两个相等的字符串具有相等的哈希值。因此,通过使用hashCode(),我们可以立即看到两个字符串是不相等的。

我只是认为使用hashCode()可以是一个很好的过滤器equals

更新2:这里有一些代码,关于我们在这里谈论的。

这是一个字符串方法等于如何看起来像这样的例子

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        if (hashCode() == anotherString.hashCode()){
            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;
            }
        }else{
            return false;
        }
    }
    return false;
}

答案 1

哈希码可能是不平等的第一轮检查。但是,它提出了一些权衡。

  1. String哈希码是懒惰计算的,尽管它们确实使用“保护”值。如果你正在比较具有长生存期的字符串(即,它们可能已经计算了哈希码),这不是问题。否则,您只能计算哈希码(可能很昂贵),或者在尚未计算哈希码时忽略检查。如果您有很多短期字符串,那么忽略检查的频率将高于使用它的频率。
  2. 在现实世界中,大多数字符串的前几个字符都不同,因此您首先检查哈希码不会节省太多。当然,也有例外(例如URL),但同样,在现实世界的编程中,它们很少发生。

答案 2

这个问题实际上已经被JDK的开发人员考虑过了。我无法在各种消息中找到为什么它没有包括在内。该增强功能也列在 bug 数据库中

也就是说,建议的更改之一是:

public boolean equals(Object anObject) {
    if (this == anObject) // 1st check identitiy
        return true;
    if (anObject instanceof String) { // 2nd check type
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) { // 3rd check lengths
            if (n != 0) { // 4th avoid loading registers from members if length == 0
                int h1 = hash, h2 = anotherString.hash;
                if (h1 != 0 && h2 != 0 && h1 != h2) // 5th check the hashes
                    return false;

还有一个讨论用于实习字符串(即,如果两个字符串都被拘留:)。==if (this != anotherString) return false;