Равный объект в Java

#java

#java

Вопрос:

Итак, это из Java Head First (страница 563)

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

Но, я думаю, простой тест опровергнет это.

 public class Song {

    private String name;

    public Song(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }


    @Override
    public boolean equals(Object obj) {
        Song objectSong = (Song) obj;
        return this.getName().equals(objectSong.getName());
    }

}
  

Что ж, это вернет true:

 Song songA = new Song("A","B");
Song songB = new Song("A","C");

System.out.println(songA.equals(songB));
  

Я что-то упускаю? О чем пытается мне рассказать книга?

Комментарии:

1. Прямо перед частью, которую вы процитировали, говорится: «если вы переопределяете equals(), вы ДОЛЖНЫ переопределить hashCode()».

2. @Robert Извините, я не понимаю, что вы пытаетесь сказать этим комментарием?

3. На странице 563 говорится «если вы переопределяете equals(), вы ДОЛЖНЫ переопределить hashCode()» и «если вы не переопределяете hashCode(), никакие два объекта не могут считаться равными». Итак, если вы не переопределяете hashCode(), вы НЕ ДОЛЖНЫ переопределять equals () , и, следовательно, никакие два объекта не могут считаться равными.

4. @Robert В моем вопросе я доказываю, что я могу заставить 2 объекта считаться равными без переопределения хэш-кода?

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

Ответ №1:

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

Вы неправильно интерпретируете. Автор не говорит, что метод (это все equals и hashCode есть) не может возвращать true для двух разных объектов. Они говорят, что семантически два объекта не должны считаться равными, если результат их hashCode не равен. Они описывают, как hashCode следует использовать. Если вы используете его по-другому, вы можете получить странные и неожиданные результаты.

Комментарии:

1. 1. Например, HashSet только рассматривает equals вызов, выполняемый для объектов с совпадающим хэш-кодом. Пока хэш-коды не совпадают, они все равно не могут быть равны.

Ответ №2:

Вам нужно переопределить hashcode, чтобы класс вел себя как ожидалось с коллекциями на основе hashcode (и чем-либо еще).

Например, что произойдет, если вы поместите свою песню в HashSet, а затем попытаетесь вставить другую?

Вы всегда должны переопределять хэш-код, если вы переопределяете equals, и наоборот. Убедитесь, что они согласованы.

(джош Блох, эффективная java, является хорошей отправной точкой)

Ответ №3:

В Java каждый объект имеет доступ к методу equals(), поскольку он наследуется от класса Object. Однако эта реализация по умолчанию просто сравнивает адреса памяти объектов. Вы можете переопределить реализацию метода equals() по умолчанию, определенную в java.lang.Объект. Если вы переопределяете equals(), вы также должны переопределить hashCode(). В противном случае произойдет нарушение общего контракта для Object.hashCode, что может иметь неожиданные последствия, когда ваш класс находится в сочетании со всеми коллекциями на основе хэша.

Источник: http://www.xyzws.com/javafaq/why-always-override-hashcode-if-overriding-equals/20 (взгляните на него, в нем есть хорошие примеры).

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