11 ответов:
Как правило, hashCode () просто возвращает адрес объекта в памяти, если вы не переопределяете его.
с 1:
насколько это разумно практично, метод hashCode, определенный объектом класса, возвращает различные целые числа для различных объектов. (Это обычно реализуется путем преобразования внутренний адрес объекта в целое число, но этот метод реализации не требуется на языке программирования javatm.)
в HotSpot JVM по умолчанию при первом вызове ненагруженного
Object.hashCodeилиSystem.identityHashCodeслучайное число генерируется и хранится в заголовке объекта. Последующие вызовыObject.hashCodeилиSystem.identityHashCodeпросто извлечь это значение из заголовка. По умолчанию он не имеет ничего общего с содержимым объекта или местоположением объекта, просто случайное число. Это поведение контролируется-XX:hashCode=nHotSpot JVM опция, которая имеет следующие возможные значения:
- 0: используйте глобальный случайный генератор. Это значение по умолчанию в Java 7. Он имеет тот недостаток, что одновременные вызовы из нескольких потоков могут вызвать состояние гонки, которое приведет к созданию одного и того же хэш-кода для разных объектов. Также в высококонкурентной среде возможны задержки из-за конкуренции (использование одной и той же области памяти из разных ядер процессора).
- 5: Используйте некоторый поток-локальный генератор случайных чисел xor-shift, который свободен от предыдущих недостатков. Это значение по умолчанию в Java 8.
- 1: Используйте указатель объекта, смешанный с некоторым случайным значением, которое изменяется на событиях" stop-the-world", поэтому между событиями stop-the-world (например, сборкой мусора) генерируемые хэш-коды стабильны (для целей тестирования/отладки)
- 2: всегда использовать
1(для тестирования/отладки)- 3: Используйте autoincrementing номера (для целей испытания / отладки, также глобальный счетчик использован, таким образом условия состязания и гонки возможно)
- 4: при необходимости используйте указатель объекта, обрезанный до 32 бит (для тестирования/отладки)
обратите внимание, что даже если вы установите
-XX:hashCode=4, хэш-код не всегда будет указывать на адрес объекта. Объект может быть перемещен позже, но хэш-код останется прежним. Кроме того, адреса объектов плохо распределены (если ваше приложение использует не так много памяти, большинство объектов будут расположены близко друг к другу), поэтому вы можете получить несбалансированные хэш-таблицы, если вы используете эта опция.
реализация
hashCode()может отличаться от класса к классу, но договор наhashCode()очень конкретно и ясно и явно указано в Javadocs:возвращает значение хэш-кода для объекта. Этот метод поддерживается в интересах хэш-таблиц, таких как те, которые предоставляются java.утиль.коллекция Hashtable.
общий контракт хэш-кода:
- всякий раз, когда он вызывается на один и тот же объект более одного раза во время выполнения приложения Java, метод hashCode должен последовательно возвращать одно и то же целое число, при условии, что никакая информация, используемая в равных сравнениях на объекте, не изменяется. Это целое число не должно оставаться последовательным от одного выполнения приложения к другому выполнению того же приложения.
- если два объекта равны в соответствии с методом equals(Object), то вызов метода hashCode для каждого из двух объектов должен дать тот же самый целочисленный результат.
- не требуется, чтобы два объекта были неравными в соответствии с равными (java.ленг.Object) метод, затем вызывая метод hashCode на каждом из двух объектов должен привести к отличным целочисленные результаты. Однако программист должен знать, что получение различных целочисленных результатов для неравных объектов может улучшить производительность хэш-таблиц.
насколько это разумно практично, метод хэш-кода определен по классу Object возвращает различные целые числа для различных объектов. (Это обычно реализуется путем преобразования внутренний адрес объекта в целое число, но этот метод реализации не требуется на языке программирования javatm.)
hashCode()тесно связан сequals()и если вы переопределяетеequals(), вы также должны переопределитьhashCode().
Если хэш-код не переопределен, вы вызовете хэш-код объекта, вот отрывок из его javadoc:
насколько это разумно практично, метод hashCode, определенный объектом класса, возвращает различные целые числа для различных объектов. (Это обычно реализуется путем преобразования внутренний адрес объекта в целое число, но этот метод реализации не требуется на языке программирования javatm.)
реализация хэш-кода по умолчанию дает внутренний адрес объекта в jvm, как 32-битное целое число. Таким образом, два разных (в памяти) объекта будут иметь разные хэш-коды.
Это согласуется с реализацией по умолчанию equals. Если вы хотите переопределить equals для своих объектов, вам придется адаптировать хэш-код, чтобы они были согласованы.
см.http://www.ibm.com/developerworks/java/library/j-jtp05273.html для хорошего обзор.
вы должны попытаться реализовать хэш-код, чтобы разные объекты давали разные результаты. Я не думаю, что есть стандартный способ сделать это.
читать эту статью для некоторых информация.
хэш-код полезен для хранения объекта в коллекции, например хэш-набора. Позволяя объекту определять хэш-код как нечто уникальное, он позволяет алгоритму хэш-набора эффективно работать.
сам объект использует адрес объекта в памяти, который очень уникален, но может быть не очень полезен, если два разных объекта (например, две одинаковые строки) должны считаться одинаковыми, даже если они дублируются в памяти.
два объекта с разным хэш-кодом не должны быть равны относительно equals ()
a.hashCode() != b.hashCode()означает!a.equals(b)однако два объекта, которые не равны относительно equals (), могут иметь один и тот же хэш-код. Хранение этих предметов в наборе или карте станет менее эффективным, если многие объекты имеют одинаковый хэш-код.
Не совсем ответ, но добавление к моему предыдущему комментарию
внутренний адрес объекта не может гарантированно оставаться неизменным в JVM, сборщик мусора которого может перемещать его во время уплотнения кучи.
Я пытался сделать что-то вроде этого:
public static void main(String[] args) { final Object object = new Object(); while (true) { int hash = object.hashCode(); int x = 0; Runtime r = Runtime.getRuntime(); List<Object> list = new LinkedList<Object>(); while (r.freeMemory() / (double) r.totalMemory() > 0.3) { Object p = new Object(); list.add(p); x += object.hashCode();//ensure optimizer or JIT won't remove this } System.out.println(x); list.clear(); r.gc(); if (object.hashCode() != hash) { System.out.println("Voila!"); break; } } }но хэш-код действительно не меняется... может кто-нибудь сказать мне, как JDK Sun на самом деле реализует Obect.хэш-код?
возвращает 6-значный шестнадцатеричный номер. Обычно это место в памяти слота, к которому адресуется объект. Из алгоритмического per-se я предполагаю, что JDK делает двойное хэширование (собственная реализация), которое является одной из лучших функций хэширования для открытой адресации. Эта двойная схема хеширования сильно уменьшает возможность столкновений.
следующий пост даст поддерживающую идею -
Java-HashMap путаница в обработке столкновений и get() метод
вы должны переопределить хэш-код в каждом классе, который переопределяет equals. невыполнение этого требования приведет к нарушению генерального контракта на объект.хэш-код, который будет препятствовать правильному функционированию вашего класса в
conjunction with all hash-based collections,including HashMap, HashSet, and Hashtable.
Comments