Создать уникальный хэш-код на основе многих значений - PullRequest
0 голосов
/ 07 января 2019

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

private int id_place;
private String algorithm;
private Date mission_date;
private int mission_hour;
private int x;
private int y;

Я вычисляю hashCode следующим образом:

id_place * (7 * algorithm.hashCode()) + (31 * mission_date.hashCode()) + (23 * mission_hour + 89089) + (x * 19 + 67067) + (y * 11 + 97097);

Как я могу превратить его в уникальный хэш-код? Я не уверен, что это уникально ...

Ответы [ 5 ]

0 голосов
/ 07 января 2019

Поскольку у вас есть несколько полей, используйте:

public int hashCode() {
    return Objects.hash(id_place, algorithm, mission_date, mission_hour, x, y);
}

Если objA.equals (objB) имеет значение true, то objA и objB должны возвращать один и тот же хэш-код. Если objA.equals (objB) имеет значение false, то objA и objB могут возвращать один и тот же хеш-код, если ваш алгоритм хэширования в этом случае возвращает разные хеш-коды, это хорошо по соображениям производительности.

 public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    ClassA classA = (ClassA) o;
    return id_place == classA.id_place &&
            mission_hour == classA.mission_hour &&
            x == classA.x &&
            y == classA.y &&
            Objects.equals(algorithm, classA.algorithm) &&
            Objects.equals(mission_date, classA.mission_date);
}
0 голосов
/ 07 января 2019

Уникальное требование не является жестким, но чем уникальнее хэш-код, тем лучше.

Обратите внимание, что вначале хэш-код используется для HashMap в качестве индекса в «корзину». Следовательно, оптимально это должно быть уникально по модулю размера корзины, количества слотов в корзине. Однако это может измениться, когда карта увеличивается.

Но ладно, к оптимальному хеш-коду:

  • Диапазоны важны; если x и y где в 0..255, то они могут быть уникально упакованы в два байта, или когда 0..999, то y * 1000 + x. Для LocalDateTime, если можно взять длинный в секундах (то есть мс или нс), и с 2012-01-01, вы можете принять диапазон от 0 до, скажем, двух лет в будущем.
  • Вы можете изучить существующие или создать достоверные данные испытаний. Затем можно математически оптимизировать функцию хеш-кода по их совпадающим коэффициентам (7, 13, 23). Это линейная оптимизация, но это также можно сделать простым методом проб и ошибок: подсчитать количество столкновений на переменную (A, B, C).

    //int[] coeffients = ...;
    int[][] coefficientsCandidates = new int[NUM_OF_CANDIDATES][NUM_OF_COEFFS];
    ...
    int[] collisionCounts = new int[NUM_OF_CANDIDATES];
    for (Data data : allTestData) {
        ... update collisionCounts for every candidate
    }
    ... take the candidate with smallest collision count
    ... or sort by collisionCounts and pick other candidates to try out
    

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

Но также нужно честно сказать, что все эти усилия, вероятно, действительно не нужны.

0 голосов
/ 07 января 2019

В Eclipse есть функция, которая генерирует метод public int hashCode() для вас. Я использовал предоставленные вами атрибуты класса, и результат выглядит следующим образом:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((algorithm == null) ? 0 : algorithm.hashCode());
    result = prime * result + id_place;
    result = prime * result + ((mission_date == null) ? 0 : mission_date.hashCode());
    result = prime * result + mission_hour;
    result = prime * result + x;
    result = prime * result + y;
    return result;
}

Это очень похоже на ваш расчет. Однако, как указал Энди Тернер в комментарии к вашему вопросу и Эран в ответе, вы просто не можете создать уникальный хэш-код для каждого отдельного экземпляра объекта, если их количество превышает максимальное количество возможных различных хеш-кодов.

0 голосов
/ 07 января 2019

HashCode для двух разных объектов не обязательно должен быть уникальным. Согласно https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode() -

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

Таким образом, вам не нужно создавать функцию hashCode (), которая каждый раз возвращает отличный хеш-код.

0 голосов
/ 07 января 2019

Он не должен быть уникальным и не может быть уникальным. hashCode() возвращает int (32 бита), что означает, что он может быть уникальным, если у вас есть только одно свойство int и больше ничего.

Класс Integer может иметь (и имеет) уникальный hashCode(), но немногие другие классы имеют.

Поскольку у вас есть несколько свойств, некоторые из которых int, hashCode(), являющаяся функцией этих свойств, не может быть уникальной.

Вы должны стремиться к функции hasCode(), которая дает широкий диапазон различных значений для различных комбинаций ваших свойств, но она не может быть уникальной.

...