как кэширование хэш-кода работает в Java, как предложил Джошуа блох в эффективной java?
у меня есть следующий фрагмент кода из эффективной java Джошуа Блоха (пункт 9, Глава 3, стр. 49)
Если класс является неизменяемым и стоимость вычисления хэш-код важно, вы можете рассмотреть возможность кэширования хэш-кода в объекте вместо того, чтобы пересчитывать его каждый раз, когда он запрашивается. Если ты веришь ... что большинство объектов этого типа будут использоваться как хэш-ключи, то вы следует вычислить хэш-код при создании экземпляра. Иначе, можно лениво инициализировать его в первый раз вызывается хэш-код (пункт 71). Не ясно, что наш номер телефона класс заслуживает этого лечения, но просто чтобы показать вам, как это делается:
// 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;
}
мой вопрос в том, как кэширование (запоминание хэш-кода) работает здесь. В самый первый раз, hashCode()
вызывается метод, нет hashCode
назначить его результату. краткое объяснение того, как работает это кэширование, будет отличным.
Спасибо
3 ответов
простой. Прочитайте мои встроенные комментарии ниже...
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;
}
на hashCode
переменная в переменной экземпляра, и она не инициализируется явно,таким образом, Java intializes его в 0
(JLS раздел 4.12.5). Сравнение result == 0
фактически проверка, чтобы увидеть, если result
был назначен предположительно ненулевой хэш-код. Если он еще не был назначен, то он выполняет вычисление, иначе он просто возвращает ранее вычисленный хэш-код.
Если бы вы действительно хотели, чтобы это работало правильно, вы бы поставили другую переменную volatile boolean под названием isHashInvalid. Каждый сеттер, включающий значения, доступные в вашей хэш-функции, будет устанавливать эту переменную. Затем он становится, (нет необходимости проверять " 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;
}