Как хэш-код () вычислен в Java

Что значение делает hashCode() возврат метода в Java?

Я считал, что это - ссылка памяти объекта... Значение хэш-функции для new Integer(1) 1; значение хэш-функции для String("a") 97.

Я смущен: это - ASCII или какое значение?

51
задан Sebastian Nielsen 30 October 2019 в 22:45
поделиться

6 ответов

Хэш-код - это целочисленное значение, которое представляет состояние объекта, для которого был вызван хэш-код. Поэтому Integer, установленный в 1, вернет хэш-код "1", потому что хэш-код Integer и его значение - одно и то же. Хэш-код символа равен его коду ASCII. Если вы пишете пользовательский тип, вы несете ответственность за создание хорошей реализации hashCode, которая будет наилучшим образом представлять состояние текущего экземпляра.

44
ответ дан 7 November 2019 в 09:55
поделиться

Значение, возвращаемое функцией hashCode () , ни в коем случае не является гарантированным адресом памяти объекта. Я не уверен в реализации в классе Object , но имейте в виду, что большинство классов переопределят hashCode () , так что два экземпляра, которые семантически эквивалентны (но не совпадают instance) будет хешировать с тем же значением. Это особенно важно, если классы могут использоваться в другой структуре данных, такой как Set, которая зависит от hashCode , согласованного с равным .

Не существует hashCode () , который однозначно идентифицирует экземпляр объекта, несмотря ни на что. Если вам нужен хэш-код, основанный на базовом указателе (например, в реализации Sun), используйте System.identityHashCode () - это будет делегировать методу hashCode по умолчанию, независимо от того, был ли он переопределено.

Тем не менее, даже System.identityHashCode () может возвращать один и тот же хеш для нескольких объектов. См. Комментарии для объяснения, но вот пример программы, которая непрерывно генерирует объекты, пока не найдет два с одинаковым System.identityHashCode () . Когда я запускаю его, он быстро находит два System.identityHashCode () , которые совпадают, в среднем после добавления на карту около 86 000 объектов-оболочек типа Long (и целочисленных оболочек для ключа).

public static void main(String[] args) {
    Map<Integer,Long> map = new HashMap<>();
    Random generator = new Random();
    Collection<Integer> counts = new LinkedList<>();

    Long object = generator.nextLong();
    // We use the identityHashCode as the key into the map
    // This makes it easier to check if any other objects
    // have the same key.
    int hash = System.identityHashCode(object);
    while (!map.containsKey(hash)) {
        map.put(hash, object);
        object = generator.nextLong();
        hash = System.identityHashCode(object);
    }
    System.out.println("Identical maps for size:  " + map.size());
    System.out.println("First object value: " + object);
    System.out.println("Second object value: " + map.get(hash));
    System.out.println("First object identityHash:  " + System.identityHashCode(object));
    System.out.println("Second object identityHash: " + System.identityHashCode(map.get(hash)));
}

Пример вывода:

Identical maps for size:  105822
First object value: 7446391633043190962
Second object value: -8143651927768852586
First object identityHash:  2134400190
Second object identityHash: 2134400190
45
ответ дан 7 November 2019 в 09:55
поделиться

Object.hashCode (), если память обслуживает правильно (проверьте JavaDoc на наличие java.lang.Object), зависит от реализации и будет меняться в зависимости от объекта (Sun JVM получает значение из значения ссылки к объекту).

Обратите внимание, что если вы реализуете какой-либо нетривиальный объект и хотите правильно сохранить его в HashMap или HashSet, вы ДОЛЖНЫ переопределить hashCode () и equals (). hashCode () может делать все, что вам нравится (это совершенно законно, но неоптимально, чтобы он возвращал 1.), но жизненно важно, чтобы если ваш метод equals () возвращал true, тогда значение, возвращаемое hashCode () для обоих объектов, было одинаковым.

Путаница и непонимание hashCode () и equals () - большой источник ошибок. Убедитесь, что вы тщательно ознакомились с JavaDocs для Object.hashCode () и Object.equals (), и я гарантирую, что потраченное время окупится.

2
ответ дан 7 November 2019 в 09:55
поделиться

Метод hashCode () часто используется для идентификации объекта. Я думаю, что реализация Object возвращает указатель (не реальный указатель, а уникальный идентификатор или что-то в этом роде) объекта. Но большинство классов переопределяют метод. Подобно классу String . Два объекта String имеют разные указатели, но они равны:

new String("a").hashCode() == new String("a").hashCode()

Я думаю, что наиболее часто hashCode () используется в Hashtable , HashSet , так далее..

Java API Object hashCode ()

Изменить: (из-за недавнего отрицательного голоса и на основе статьи, которую я читал о параметрах JVM)

С параметром JVM -XX: hashCode вы можете изменить способ вычисления hashCode (см. выпуск 222 бюллетеня Java Specialists 'Newsletter).

HashCode == 0: просто возвращает случайные числа, не имеющие отношения к тому, где в памяти находится объект. Насколько я понимаю, глобальное чтение-запись начального числа не оптимально для систем с большим количеством процессоров .

HashCode == 1: подсчитывает значения хэш-кода, не знаю, с какого значения они начинаются, но кажется довольно большим.

HashCode == 2: всегда возвращает один и тот же хэш-код идентичности, равный 1. Это можно использовать для тестирования кода, который полагается на идентичность объекта. причина, по которой JavaChampionTest вернула URL Кирка в приведенном выше примере , заключается в том, что все объекты возвращали один и тот же хэш-код.

HashCode == 3: Подсчитывает значения хэш-кода, начиная с нуля. Он не выглядит поточно-ориентированным, поэтому несколько потоков могут генерировать объекты с одним и тем же хеш-кодом.

HashCode == 4: Похоже, это имеет какое-то отношение к области памяти , в которой был создан объект.

HashCode> = 5: это алгоритм по умолчанию для Java 8 и имеет начального числа для каждого потока. Он использует схему xor-shift Марсальи для получения псевдослучайных чисел.

7
ответ дан 7 November 2019 в 09:55
поделиться

Я читал, что это ссылка на объект в памяти ..

Нет. Object.hashCode () использовался для возврата адреса памяти около 14 лет назад. Не с.

какой тип значения

Что это такое, полностью зависит от того, о каком классе вы говорите, и от того, переопределил ли он `Object.hashCode ().

5
ответ дан 7 November 2019 в 09:55
поделиться

Если вы хотите узнать, как они применяются, я предлагаю вам прочитать исходный текст. Если вы используете IDE, вы можете просто + на интересующем вас методе и посмотреть, как метод реализован. Если вы не можете этого сделать, вы можете найти источник в Google.

Например, Integer.hashCode() реализован как

   public int hashCode() {
       return value;
   }

и String.hashCode()

   public int hashCode() {
       int h = hash;
       if (h == 0) {
           int off = offset;
           char val[] = value;
           int len = count;

           for (int i = 0; i < len; i++) {
               h = 31*h + val[off++];
           }
           hash = h;
       }
       return h;
   }
22
ответ дан 7 November 2019 в 09:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: