Создание метода hashCode() - Java

У меня возникли проблемы с написанием метода hashCode() для созданного мной класса. Этот класс предназначен для использования внутри TreeSet, и, таким образом, он реализует Comparable. Класс имеет следующие переменные:

public class Node implements Comparable<Node> {
   Matrix matrix;
   int[] coordinates= new int[2];
   Node father;
   int depth;
   int cost;

Здесь выполняется реализация метода compareTo(). Я хочу, чтобы TreeSet организовал эти структуры Node по их стоимости, поэтому compareTo() возвращает результат простого вычитания.

public int compareTo(Node nodeToCompare) {
    return this.cost - nodeToCompare.cost;
}

Я также реализовал метод equals().

public boolean equals(Object objectToCompare) {
    if(objectToCompare== this) {return true;}
    if(objectToCompare== null || objectToCompare.getClass()!= this.getClass()) {return false;}

    Node objectNode= (Node) objectToCompare;
    return this.father.equals(objectNode.father) &&
            this.depth== objectNode.depth &&
            this.cost== objectNode.cost &&
            this.matrix.equals(objectNode.matrix) &&
            Arrays.equals(this.coordinates, objectNode.coordinates);
}

Сказав все это, у меня есть несколько вопросов:

  • Поскольку я реализовал новый метод equals(), должен ли я реализовать новый метод hashCode()?
  • Как я могу реализовать новый хэш-код method() с этими переменными? (Обратите внимание, что переменная матрица типа Matrix имеет реализованный метод hashCode())

Что все!

Ответы

Ответ 1

Ваш метод compareTo не согласуется с вашим методом equals: ваш метод compareTo говорит, что два экземпляра эквивалентны, если они имеют одинаковый cost — такой, что a TreeSet может содержать только не более одного экземпляра с данным cost — но ваш метод equals говорит, что они эквивалентны, если они имеют один и тот же cost и одинаковы с другими способами.

Итак, предположим, что ваш метод equals верен:

  • вам нужно исправить свой метод compareTo, чтобы он был совместим с ним.
  • вам нужно создать метод hashCode, соответствующий этому. Я рекомендую использовать ту же логику, что используется java.util.List.hashCode(), что является простым и эффективным способом сборки хэш-кодов объекты компонента в определенном порядке; в основном вы должны написать что-то вроде:
    int hashCode = 1;
    hashCode = 31 * hashCode + (father == null ? 0 : father.hashCode());
    hashCode = 31 * hashCode + depth;
    hashCode = 31 * hashCode + cost;
    hashCode = 31 * hashCode + matrix.hashCode();
    hashCode = 31 * hashCode + java.util.Arrays.hashCode(coordinates);
    return hashCode;

Ответ 2

Intellij IDEA может сделать это как функцию "правой кнопки мыши". Просто увидев, что это сделано правильно, вы научите вас много.

И вы должны переопределить оба в любом случае.

Ответ 3

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

Глядя на ваш метод equals (который требует переменный перевод btw), вы можете добавить хэш-коды всех внутренних переменных-членов, которые должны быть равны для вашего метода equals, чтобы дать true. например.

public int hashCode() {
    return this.matrix.hashCode() + 
           this.coordinates[0] + 
           this.coordinates[1] + 
           this.father.hashCode() +
           this.depth + this.cost;               
}

Вышеприведенное предполагает, что матрица и отец никогда не являются нулями, вам нужно убедиться, что вы проверяете нули, если это не так.

Если вы чувствуете себя более предприимчивыми, вы можете размножить несколько из вышеперечисленных с простым, чтобы убедиться, что вы не получаете столкновений hashCode для разных данных (это поможет повысить производительность, если вы используете свой класс в хэш-таблицах и хэш-картах). Если вам нужно обслуживать нули, описанный выше метод может быть написан немного лучше:

public int hashCode() {
    return ((this.matrix == null) ? 0 : this.matrix.hashCode()) + 
           17 * this.coordinates[0] + 
           this.coordinates[1] + 
           ((this.father == null) ? 0 : this.father.hashCode()) +
           31 * this.depth + 19 * this.cost;               
}

Ответ 4

Если ваша коллекция мала, вы можете вернуть константу из метода hashCode. Он используется для быстрого поиска. hashCodes походит на блоки, в которых хранятся элементы. Правила:

  • Равные элементы должны быть в одной коробке (имеют один и тот же hashCode) - конечно;
  • Не равные элементы могут быть как в одном, так и в разных блоках.

Затем вы возвращаете константу, вы подчиняетесь этим двум правилам, но это может значительно снизить производительность на небольших списках (поскольку JVM будет искать во всех элементах, а не только в элементах в одной и той же коробке). Но обратная константа - плохой подход.

PS: Извините за мое письмо. Английский не мой родной язык.

PPS: обычно вы должны реализовать метод hashCode таким же образом, как equals (использовать те же элементы)