@ Эриксон более или менее правильно.Хэш-код, возвращаемый java.lang.Object.hashCode()
, не изменяется в течение времени жизни объекта.
Способ, которым это (обычно) реализуется, довольно умный.Когда объект перемещается сборщиком мусора, его оригинальный хеш-код должен храниться где-то на случай, если он будет использован снова.Очевидный способ реализовать это - добавить 32-битное поле в заголовок объекта для хранения хеш-кода.Но это добавило бы 1 слово к каждому объекту и потратило бы место в наиболее распространенном случае ... где метод Object hashCode
не вызывается.
Решение состоит в том, чтобы добавить два бита флага кслово флага объекта и используйте их (примерно) следующим образом.Первый флаг устанавливается при вызове метода hashCode
.Второй флаг сообщает методу hashCode
, использовать ли текущий адрес объекта в качестве хеш-кода или использовать сохраненное значение.Когда GC запускается и перемещает объект, он проверяет эти флаги.Если первый флаг установлен, а второй не установлен, GC выделяет одно дополнительное слово в конце объекта и сохраняет исходное местоположение объекта в этом слове.Затем он устанавливает два флага.С тех пор метод hashCode
получает значение хэш-кода из слова в конце объекта.
Фактически реализация identityHashCode
1014 * должна вести себя так чтобы выполнить следующую часть общего контракта хэш-кода :
"Всякий раз, когда он вызывается для одного и того же объекта более одного раза во время выполнения приложения Java,метод hashCode должен последовательно возвращать одно и то же целое число, при условии, что никакая информация, используемая в сравнениях сравнения для объекта, не изменяется . Это целое число не должно оставаться согласованным от одного выполнения приложения до другого выполнения того же приложения. "
Гипотетическая реализация identityHashCode()
, которая просто возвращает текущий машинный адрес объекта, будет нарушать подсвеченную часть, если / когда GC переместит объект вдругой адрес.Единственный способ избежать этого - для (гипотетической) JVM гарантировать, что объект никогда не будет двигаться после того, как к нему был вызван hashCode
.И это может привести к серьезным и неразрешимым проблемам с фрагментацией кучи.