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