Что такое хеш-код объекта, если hashCode () не переопределен? - PullRequest
62 голосов
/ 10 февраля 2010

Если метод hashCode () не переопределен, каков будет результат вызова hashCode () для любого объекта в Java?

Ответы [ 11 ]

53 голосов
/ 08 сентября 2015

В JVM HotSpot по умолчанию при первом вызове не перегруженного Object.hashCode или System.identityHashCode случайное число генерируется и сохраняется в заголовке объекта. Последующие вызовы Object.hashCode или System.identityHashCode просто извлекают это значение из заголовка. По умолчанию он не имеет ничего общего с содержимым объекта или местоположением объекта, только случайное число. Это поведение контролируется опцией -XX:hashCode=n HotSpot JVM, которая имеет следующие возможные значения:

  • 0: использовать глобальный генератор случайных чисел. Это настройка по умолчанию в Java 7. Недостатком является то, что одновременные вызовы из нескольких потоков могут вызвать состояние гонки, что приведет к генерации одного и того же hashCode для разных объектов. Также в высококонкурентной среде возможны задержки из-за конкуренции (при использовании одной и той же области памяти от разных ядер ЦП).
  • 5: использовать некоторый локальный для потока генератор случайных сдвигов xor, который свободен от предыдущих недостатков. Это настройка по умолчанию в Java 8.
  • 1: использовать указатель объекта, смешанный с некоторым случайным значением, которое изменяется в событиях «остановка мира», поэтому между событиями «остановка мира» (такими как сборка мусора) сгенерированные хэш-коды стабильны (для целей тестирования / отладки )
  • 2: всегда использовать 1 (для целей тестирования / отладки)
  • 3: использовать автоинкрементные числа (для целей тестирования / отладки также используется глобальный счетчик, поэтому возможны состязания и условия гонки)
  • 4: при необходимости использовать указатель объекта, обрезанный до 32 бит (для целей тестирования / отладки)

Обратите внимание, что даже если вы установите -XX:hashCode=4, hashCode не всегда будет указывать на адрес объекта. Объект может быть перемещен позже, но hashCode останется прежним. Также адреса объектов плохо распределены (если ваше приложение использует не так много памяти, большинство объектов будет располагаться близко друг к другу), поэтому вы можете получить несбалансированные хеш-таблицы, если будете использовать эту опцию.

34 голосов
/ 10 февраля 2010

Обычно hashCode () просто возвращает адрес объекта в памяти, если вы не переопределите его.

С 1 :

Насколько это практически целесообразно, метод hashCode, определенный классом Object, возвращает разные целые числа для разных объектов. (Обычно это реализуется путем преобразования внутреннего адреса объекта в целое число, но этот метод реализации не требуется языком программирования JavaTM.)

13 голосов
/ 10 февраля 2010

Реализация hashCode() может отличаться от класса к классу, но контракт на hashCode() очень конкретен и четко и ясно указан в Javadocs :

Возвращает значение хеш-кода для объекта. Этот метод поддерживается для использования хеш-таблиц, таких как те, которые предоставляются java.util.Hashtable.

Общий контракт hashCode:

  • Всякий раз, когда он вызывается для одного и того же объекта более одного раза во время выполнения приложения Java, метод hashCode должен последовательно возвращать одно и то же целое число при условии, что никакая информация, используемая в сравнениях сравнения объекта, не изменяется. Это целое число не должно оставаться согласованным при выполнении одного приложения другим исполнением того же приложения.
  • Если два объекта равны в соответствии с методом equals (Object), то вызов метода hashCode для каждого из двух объектов должен давать одинаковый целочисленный результат.
  • Не требуется, чтобы, если два объекта были неравны в соответствии с методом equals (java.lang.Object), то вызов метода hashCode для каждого из этих двух объектов должен давать разные целочисленные результаты. Тем не менее, программист должен знать, что выдача различных целочисленных результатов для неравных объектов может повысить производительность хеш-таблиц.

Насколько это практически целесообразно, метод hashCode, определенный классом Object, возвращает разные целые числа для разных объектов. (Это обычно реализуется путем преобразования внутреннего адреса объекта в целое число, но этот метод реализации не требуется языком программирования JavaTM.)

hashCode() тесно связан с equals(), и если вы переопределите equals(), вы также должны переопределить hashCode().

3 голосов
/ 10 февраля 2010

Если хеш-код не переопределен, вы назовете хеш-код объекта, вот выдержка из его javadoc:

Насколько разумно, метод hashCode, определенный классом Object, возвращает разные целые числа для разных объектов. (Это обычно реализуется путем преобразования внутреннего адреса объекта в целое число, но этот метод реализации не требуется языком программирования JavaTM.)

1 голос
/ 30 ноября 2014

Вы должны переопределить hashCode в каждом классе, который переопределяет равные. Невыполнение этого приведет к нарушению общего контракта для Object.hashCode, что помешает правильной работе вашего класса в conjunction with all hash-based collection с including HashMap, HashSet, and Hashtable.

1 голос
/ 10 февраля 2010

реализация хеш-кода по умолчанию дает внутренний адрес объекта в jvm в виде 32-битного целого числа. Таким образом, два разных (в памяти) объекта будут иметь разные хеш-коды.

Это согласуется с реализацией equals по умолчанию. Если вы хотите переопределить equals для ваших объектов, вам придется адаптировать hashCode, чтобы они были согласованными.

См. http://www.ibm.com/developerworks/java/library/j-jtp05273.html для хорошего обзора.

0 голосов
/ 17 октября 2012

возвращает шестизначное шестизначное число. Обычно это ячейка памяти слота, к которому адресован объект. Исходя из алгоритмического факта, я думаю, JDK выполняет двойное хеширование (нативная реализация), которое является одной из лучших хеш-функций для открытой адресации. Эта схема двойного хеширования значительно снижает вероятность коллизий.

Следующий пост будет поддерживать идею -

Java - путаница в HashMap по поводу обработки коллизий и метода get ()

0 голосов
/ 14 декабря 2011

Не совсем ответ, но добавление в мой предыдущий комментарий

нельзя гарантировать, что внутренний адрес объекта останется неизменным в 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.hashcode?

0 голосов
/ 10 февраля 2010

Два объекта с разными хеш-кодами не должны быть равны по отношению к equals ()

a.hashCode() != b.hashCode() должно означать !a.equals(b)

Однако два объекта, которые не равны по отношению к equals (), могут иметь одинаковый хеш-код. Хранение этих объектов в наборе или карте станет менее эффективным, если многие объекты имеют одинаковый хэш-код.

0 голосов
/ 10 февраля 2010

Хеш-код полезен для хранения объекта в коллекции, такой как хэш-набор. Позволяя объекту определять Hashcode как нечто уникальное, он позволяет алгоритму HashSet работать эффективно.

Сам объект использует адрес объекта в памяти, который является уникальным, но может быть не очень полезным, если два разных объекта (например, две одинаковые строки) следует считать одинаковыми, даже если они дублируются в памяти. *

...