Что такое хэш-код объекта, если hashCode () не переопределен?



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

290   11  

11 ответов:

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

с 1:

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

в HotSpot JVM по умолчанию при первом вызове ненагруженного Object.hashCode или System.identityHashCode случайное число генерируется и хранится в заголовке объекта. Последующие вызовы Object.hashCode или System.identityHashCode просто извлечь это значение из заголовка. По умолчанию он не имеет ничего общего с содержимым объекта или местоположением объекта, просто случайное число. Это поведение контролируется -XX:hashCode=n HotSpot 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 collection s,including HashMap, HashSet, and Hashtable.

    Ничего не найдено.

Добавить ответ:
Отменить.