Как правильно сравнивать два объекта с помощью хэш-наборов?

У меня есть класс человека, у которого есть имя и список друзей в HashSet.

Я хочу переопределить метод equals для этого класса Person. Ниже то, что я написал до сих пор.

Но я не уверен в этом, потому что знаю, что HashSet не обязательно должен быть в порядке, и я также слышал, что мне нужно переопределить метод HashCode.

Какие изменения я должен внести в приведенные ниже коды, чтобы правильно реализовать метод equals?

public boolean equals(Note target){
    if(this.name==target.getName() && this.friends == target.getFriends()){
        return true;
    }
    return false;
}

public HashSet<Person> getFriends(){
    return this.friends;
}

изменить

//override hashCode()
public int hashCode() {
    return name.hashCode() + friends.hashCode();
}

person user482594    schedule 04.09.2011    source источник
comment
Убедитесь, что вы используете правильную сигнатуру метода, если собираетесь переопределить равно (что и следует), т. е. public boolean equals(Object obj), а затем проверить правильность типа и т. д. Используя Note в качестве параметра, вы overload равно, что является чем-то другим.   -  person matsev    schedule 04.09.2011


Ответы (2)


Оператор == определенно неверен для HashSet и name. Если вы хотите сравнить объекты в java, используйте метод equals. Оператор == сравнивает внутренние идентификаторы объектов, которыми управляет JVM. Контракт для метода equals HashSet находится в документе AbstractSet.equals().

@Override
public boolean equals(Object o){

    if (o instanceof Note) {
        Note target = (Note) o;
        if(this.name.equals(target.getName()) && this.friends.equals(target.getFriends())){
            return true;
        }
    }
    return false;
}

Вы также можете проверить null, возможно, name и fiends могут быть нулевыми.

О equals и hashCode написано много. Лучший способ — просмотреть JavaDoc для lava.lang.Object.equals().

person home    schedule 04.09.2011
comment
Я получил комментарий в своем вопросе, что я должен получить (Object target) в качестве параметра. Будет ли нормально, если я все еще буду использовать (Note target) в качестве входного параметра? - person user482594; 04.09.2011
comment
Упс, я пропустил это, @matsev прав, я обновил ответ. Я также добавил аннотацию @Override, которая заставляет компилятор проверять, что Note переопределяет метод, определенный в одном из его подклассов (в данном случае java.lang.Object). - person home; 04.09.2011
comment
Эй, спасибо за вашу помощь. Я также должен переопределить метод hashCode(), верно? Я добавил hashCode в вопрос выше, отредактировав вопрос. Можете ли вы просмотреть его, если это нормально? - person user482594; 04.09.2011
comment
Без проблем. hashCode выглядит нормально. важно понимать, что хэш-код не должен гарантировать уникальность. Это помощник для встроенной в Java хэш-функции. Таким образом, вы должны разрабатывать свои методы hashCode таким образом, чтобы по возможности избегать коллизии хэшей: download.oracle.com/javase/1.5.0/docs/api/java/lang/ - person home; 04.09.2011
comment
Эй.. Я нашел здесь проблему. Если один из элементов this.friends добавил this в свой список друзей, происходит рекурсия, получающая hashCode. (если 2 друга в общих друзьях) Означает ли это, что я не должен включать друзей в hashCode отчет? - person user482594; 05.09.2011
comment
Если имя Note уникально, возврата только хэш-кода name должно быть достаточно. Может также включать size из friends. - person home; 05.09.2011

То, как вы в настоящее время настроили свой метод equals(Note), он (почти) никогда не вернет true. При работе с объектами String всегда следует использовать equals(String), а не ==.

Я бы создал свой метод Note.equals(Note) примерно так:

@Override
public boolean equals(Object obj){
    if(obj instanceof Note) {
        Note target = (Note) obj;
        if(name.equals(target.name) && friends.containsAll(target.friends)
              && friends.size() == target.friends.size()){
            return true;
        }
    }
    return false;
}

Вы заметите, что описанный выше метод equals(Note) также не выполняет friends.equals(target.getFriends()). Это потому, что вы сравниваете содержащий HashSet, а не содержимое HashSet.

Наконец, если вы хотите, чтобы ваш класс Note правильно хэшировал, вам также необходимо переопределить метод hashCode(). Подробнее об этом контракте можно прочитать в описании ссылки hashCode() в Object документация.

public int hashCode() {
    return name.hashCode() + friends.hashCode();
}
person nicholas.hauschild    schedule 04.09.2011
comment
Что делать, если у меня есть более 1 hashSet (кроме друзей), используемых в переменных класса? Я просто добавляю их в оператор hashCode()? - person user482594; 04.09.2011
comment
Если они будут использоваться для расчета вашего equals(Object) метода, то их также следует использовать в вашем hashCode() расчете. - person nicholas.hauschild; 04.09.2011
comment
Спасибо за вашу реализацию hashCode. Мне очень помогло - person user482594; 04.09.2011