2013-05-18 5 views
9

Принятый ответ в Best implementation for hashCode method дает, по-видимому, хороший метод для поиска кодов Хэша. Но я новичок в Hash Codes, поэтому я не совсем понимаю, что делать.Хорошая реализация hashCode()

Для 1) имеет значение, какое ненулевое значение я выбираю? Есть 1 так же хорошо, как и другие номера, такие как премьер 31?

Для 2), следует ли добавить каждое значение в c? Что делать, если у меня есть два поля: long, int, double и т. Д.?


ли я интерпретирую его прямо в этом классе:

public MyClass{ 
    long a, b, c; // these are the only fields 
    //some code and methods 
    public int hashCode(){ 
     return 37 * (37 * ((int) (a^(a >>> 32))) + (int) (b^(b >>> 32))) 
       + (int) (c^(c >>> 32)); 
    } 
} 

ответ

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

Есть некоторые алгоритмы, которые могут рассматриваться как не хорошо hashCode реализаций, простое добавление значений атрибутов являются одним из них. Причина этого является, если у вас есть класс, который имеет два поля, Integer, Integerб и ваш hashCode() просто суммирует эти значения, то распределение hashCode значений сильно зависит от значений вашего экземпляров магазина. Например, если большинство значений a находятся между 0-10 и b находятся между 0-10, тогда значения hashCode находятся в диапазоне от 0 до 20. Это означает, что если вы храните экземпляр этого класса, например. HashMap множество экземпляров будут храниться в том же ковше (поскольку в одном ковше будут помещены многочисленные экземпляры с разными значениями a и b). Это будет иметь плохое влияние на производительность операций на карте, потому что при выполнении поиска все элементы из ковша будут сравниваться с использованием equals().

Что касается алгоритма, она выглядит хорошо, он очень похож на тот, который генерирует Eclipse,, но использует другое простое число, 31 не 37:

@Override 
public int hashCode() { 
    final int prime = 31; 
    int result = 1; 
    result = prime * result + (int) (a^(a >>> 32)); 
    result = prime * result + (int) (b^(b >>> 32)); 
    result = prime * result + (int) (c^(c >>> 32)); 
    return result; 
} 
+0

Какой алгоритм хорош? Хороший ли пример в этом примере? Должен ли я использовать разные простые числа для каждого элемента? – Justin

+0

Я понимаю ваш # 1, но лучше иметь меньше столкновений. – Justin

+0

Любой код может быть любым, но чтобы быть * хорошим * кодом, hashCode не может быть «ничего». См. Object.hashCode() java doc – Bohemian

5

метод, хорошо себя хэш-код уже существует для длинных значений - не изобретать колесо:

int hashCode = Long.valueOf((a * 31 + b) * 31 + c).hashCode(); 

Умножив на простое число (обычно 31 в классах JDK) и сложение суммы является распространенным методом создания «уникальный» номер из нескольких номеров.

Метод hashCode() Long сохраняет результат правильно распределенным по диапазону int, делая хеш «хорошо себя вести» (в основном псевдослучайным).

+0

Это лучше, чем 'int hashCode = 31 * (31 * ((int) (a^(a >>> 32)) + 31) + (int) (b^(b> >> 32))) + (int) (c^(c >>> 32)) '? ('(int) (a^(a >>> 32))' == 'Long.valueOf (a) .hashCode()') Другими словами, лучше взять комбинацию Хэш-кодов значений или Хэш-код комбинации значений? – Justin

+4

@gangqinlaohu не знаю, но я не должен знать. Я могу гарантировать, что код JDK для хеширования будет лучше, чем все, что вы придумали. Эти классы тщательно проверяются и исследуются. Кроме того, читать мой код проще, чем ваш. Это само по себе ценно. Б) Я считаю, что было бы лучше хэш в конце (и это меньше кода), но я бы принял комбинацию (возможно, просто добавление) отдельных хешей. – Bohemian

+0

Если вы просто добавите, то 'a = 3',' b = 2', 'c = 13' вернет тот же хэш-код, что и' a = 2', 'b = 3',' c = 13' (и другие аналогичные значения) – Justin

Смежные вопросы