Я размышлял об этом в течение некоторого времени: как именно Object.GetHashCode
реализован в CLR или Java? Контракт для этого метода заключается в том, что если он вызывается для одного экземпляра объекта, он всегда должен возвращать одно и то же значение.
Обратите внимание, что я говорю о реализации по умолчанию GetHashCode (). Производные классы не обязаны переопределять этот метод. Если они решат не делать этого, они, по сути, будут иметь ссылочную семантику: равенство равно «равенству указателя» по умолчанию при использовании в хеш-таблицах & c. Это означает, что каким-то образом среда выполнения должна предоставлять постоянный хеш-код для объекта в течение всего времени его жизни.
Если машина, на которой я работаю, является 32-битной, и если экземпляр объекта никогда не перемещался в памяти, теоретически можно вернуть адрес объекта, интерпретируемый как Int32. Это было бы хорошо, поскольку все разные объекты имеют разные адреса и, следовательно, имели бы разные хэш-коды.
Тем не менее, этот подход несовершенен, среди прочего, потому что:
если сборщик мусора перемещает объект в памяти, его адрес изменяется, и его хэш-код также нарушает контракт, что хэш-код должен быть одинаковым в течение всего времени жизни объекта.
В 64-битной системе адрес объекта слишком широк, чтобы поместиться в Int32.
Поскольку управляемые объекты имеют тенденцию выравниваться с некоторой четной степенью 2, самые младшие биты всегда будут равны нулю. Это может привести к неправильным шаблонам распределения, когда хеш-коды используются для индексации в хеш-таблицу.
В .NET System.Object
состоит из блока синхронизации и дескриптора типа и ничего более, поэтому хеш-код нельзя кэшировать в самом экземпляре. Каким-то образом среда выполнения может предоставить постоянный хэш-код. Как? И как Java, Mono и другие среды выполнения делают это?