简体   繁体   English

Joshua Bloch在有效的java中建议如何在Java中使用缓存哈希码?

[英]how caching hashcode works in Java as suggested by Joshua Bloch in effective java?

I have the following piece of code from effective java by Joshua Bloch (Item 9, chapter 3, page 49) 我有以下来自Joshua Bloch的有效Java代码(第9章,第3章,第49页)

If a class is immutable and the cost of computing the hash code is significant, you might consider caching the hash code in the object rather than recalculating it each time it is requested. 如果类是不可变的并且计算哈希代码的成本很高,您可以考虑在对象中缓存哈希代码,而不是每次请求时重新计算它。 If you believe that most objects of this type will be used as hash keys, then you should calculate the hash code when the instance is created. 如果您认为此类型的大多数对象将用作哈希键,则应在创建实例时计算哈希码。 Otherwise, you might choose to lazily initialize it the first time hashCode is invoked (Item 71). 否则,您可能会在第一次调用hashCode时选择懒惰地初始化它(Item 71)。 It is not clear that our PhoneNumber class merits this treatment, but just to show you how it's done: 目前尚不清楚我们的PhoneNumber类是否值得这样做,只是为了向您展示它是如何完成的:

    // Lazily initialized, cached hashCode
    private volatile int hashCode;  // (See Item 71)
    @Override public int hashCode() {
        int result = hashCode;
        if (result == 0) {
            result = 17;
            result = 31 * result + areaCode;
            result = 31 * result + prefix;
            result = 31 * result + lineNumber;
            hashCode = result;
        }
        return result;
    }

my question is how the caching (remembering the hashCode) works here. 我的问题是如何缓存(记住hashCode)在这里工作。 The very first time, hashCode() method is called, there is no hashCode to assign it to result. 第一次调用hashCode()方法时,没有hashCode将其分配给结果。 a brief explanation on how this caching works will be great. 这个缓存如何工作的简要解释将是伟大的。 Thanks 谢谢

Simple. 简单。 Read my embedded comments below... 阅读下面的嵌入式评论......

private volatile int hashCode;
//You keep a member field on the class, which represents the cached hashCode value

   @Override public int hashCode() {
       int result = hashCode;
       //if result == 0, the hashCode has not been computed yet, so compute it
       if (result == 0) {
           result = 17;
           result = 31 * result + areaCode;
           result = 31 * result + prefix;
           result = 31 * result + lineNumber;
           //remember the value you computed in the hashCode member field
           hashCode = result;
       }
       // when you return result, you've either just come from the body of the above
       // if statement, in which case you JUST calculated the value -- or -- you've
       // skipped the if statement in which case you've calculated it in a prior
       // invocation of hashCode, and you're returning the cached value.
       return result;
   }

The hashCode variable in an instance variable, and it's not initialized explicitly, so Java intializes it to 0 (JLS Section 4.12.5) . 实例变量中的hashCode变量,并且未显式初始化, 因此Java将其初始化为0 (JLS第4.12.5节) The comparison result == 0 is in effect a check to see if result has been assigned a presumably non-zero hash code. 比较result == 0实际上是检查result是否已经分配了大概非零哈希码。 If it hasn't been assigned yet, then it performs the calculation, else it just returns the previously computed hash code. 如果尚未分配,则执行计算,否则只返回先前计算的哈希码。

If you really wanted this to work right, you'd put another volatile variable boolean called isHashInvalid. 如果你真的希望这个能正常工作,你可以使用另一个名为isHashInvalid的volatile变量boolean。 Every setter involving values accessed in your hash function would set this variable. 涉及在哈希函数中访问的值的每个setter都将设置此变量。 Then it becomes, (no need to test for '0' now): 然后就变成了,(现在不需要测试'0'):

private volatile int isHashInvalid=TRUE;
private volatile int hashCode; //Automatically zero but it doesn't matter

//You keep a member field on the class, which represents the cached hashCode value
@Override public int hashCode() {
    int result = hashCode;
    if (isHashInvalid) {
       result = 17;
       result = 31 * result + areaCode;
       result = 31 * result + prefix;
       result = 31 * result + lineNumber;
       //remember the value you computed in the hashCode member field
       hashCode = result;
       isHashInvalid=FALSE;
    }
    // when you return result, you've either just come from the body of the above
    // if statement, in which case you JUST calculated the value -- or -- you've
    // skipped the if statement in which case you've calculated it in a prior
    // invocation of hashCode, and you're returning the cached value.
    return result;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM