← Назад к вопросам

Что будет если сравнить два идентичных объекта без переопределения equals?

2.3 Middle🔥 91 комментариев
#Docker, Kubernetes и DevOps#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Сравнение объектов без переопределения equals()

Если вы сравните два семантически идентичных объекта (с одинаковыми значениями полей) без переопределения метода equals(), результат будет false, даже если данные в объектах полностью совпадают.

Поведение по умолчанию

Значение по умолчанию для метода equals() в классе Object проверяет идентичность ссылок, а не равенство содержимого:

class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

public class Main {
    public static void main(String[] args) {
        Person person1 = new Person("Иван", 30);
        Person person2 = new Person("Иван", 30);
        
        System.out.println(person1.equals(person2));  // false!
        System.out.println(person1 == person2);       // false
    }
}

Результат: false — несмотря на то, что оба объекта содержат идентичные данные.

Почему происходит именно это?

Класс Object (базовый класс для всех Java объектов) имеет реализацию equals() по умолчанию:

public boolean equals(Object obj) {
    return this == obj;  // Сравнение ссылок, а не содержимого
}

Оператор == проверяет, указывают ли обе переменные на один и тот же объект в памяти. Даже если содержимое идентично, это разные объекты в разных местах памяти.

Правильное переопределение equals()

Для корректного сравнения содержимого объектов нужно переопределить метод equals():

class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public boolean equals(Object obj) {
        // Шаг 1: проверка на идентичность ссылок
        if (this == obj) {
            return true;
        }
        
        // Шаг 2: проверка на null и тип
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        
        // Шаг 3: приведение типа и сравнение полей
        Person person = (Person) obj;
        return age == person.age && 
               Objects.equals(name, person.name);
    }
}

public class Main {
    public static void main(String[] args) {
        Person person1 = new Person("Иван", 30);
        Person person2 = new Person("Иван", 30);
        
        System.out.println(person1.equals(person2));  // true
    }
}

Использование Objects.equals() для null-безопасности

Важно: при сравнении строк или объектов, которые могут быть null, используйте Objects.equals():

// Плохо — может вызвать NullPointerException
return name.equals(person.name);

// Хорошо — безопасно обрабатывает null
return Objects.equals(name, person.name);

Контракт equals() и hashCode()

Критически важно: если вы переопределяете equals(), ОБЯЗАТЕЛЬНО переопределяйте и hashCode():

class Person {
    private String name;
    private int age;
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        
        Person person = (Person) obj;
        return age == person.age && Objects.equals(name, person.name);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

Почему это важно? Если два объекта равны по equals(), они должны иметь одинаковый hashCode. Это требование для работы с HashMap, HashSet и другими hash-based коллекциями:

Set<Person> people = new HashSet<>();
Person person1 = new Person("Иван", 30);
Person person2 = new Person("Иван", 30);

people.add(person1);
people.add(person2);

System.out.println(people.size());  // 1 (объекты считаются одинаковыми)

Сравнение в Collections

Без переопределения equals() могут возникнуть проблемы при работе с коллекциями:

List<Person> list = new ArrayList<>();
Person person1 = new Person("Иван", 30);
Person person2 = new Person("Иван", 30);

list.add(person1);

// Вернёт false, хотя логически объект уже в списке
System.out.println(list.contains(person2));

Итоговый ответ

Без переопределения equals():

  • Результат: сравнение вернёт false для семантически идентичных объектов
  • Причина: по умолчанию сравниваются ссылки на объекты (this == obj), а не их содержимое
  • Решение: переопределите equals() для сравнения значений полей
  • Помните: всегда переопределяйте hashCode() вместе с equals()
  • Используйте: Objects.equals() для null-безопасного сравнения