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

Для чего нужен equals?

1.3 Junior🔥 271 комментариев
#Kotlin основы

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

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

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

equals() в Kotlin/Java

Определение

equals() — это метод, который **сравнивает содержимое двух объектов** по смыслу, а не по ссылке в памяти. Переопределяется из базового класса Object.

Зачем нужен?

По умолчанию оператор == сравнивает ссылки на объекты:

val user1 = User("John", 25)
val user2 = User("John", 25)

// По умолчанию
user1 == user2  // false! (разные ссылки в памяти)
user1 === user2 // false! (разные объекты)

Мы хотим сравнивать по содержимому:

user1 == user2  // true! (одинаковые данные)

Реализация в Kotlin

class User(
    val name: String,
    val age: Int
) {
    override fun equals(other: Any?): Boolean {
        // Проверка типа
        if (this === other) return true
        if (other !is User) return false
        
        // Сравнение полей
        return name == other.name && age == other.age
    }
    
    override fun hashCode(): Int {
        return name.hashCode() + age.hashCode()
    }
}

val user1 = User("John", 25)
val user2 = User("John", 25)

user1 == user2  // true!

Data class (автоматический equals)

data class User(
    val name: String,
    val age: Int
)

val user1 = User("John", 25)
val user2 = User("John", 25)

user1 == user2  // true! Автоматически сгенерировано

Когда переопределять equals()?

1. Если объект используется в коллекциях:

class User(val id: Int, val name: String) {
    override fun equals(other: Any?) = other is User && id == other.id
    override fun hashCode() = id.hashCode()
}

val users = mutableSetOf<User>()
users.add(User(1, "John"))
users.add(User(1, "Jane"))  // Не добавится! Уже есть id=1

2. Если нужно сравнивать по смыслу:

data class Point(val x: Int, val y: Int)

val p1 = Point(5, 10)
val p2 = Point(5, 10)

p1 == p2  // true

3. В наследовании:

open class Entity(val id: Int) {
    override fun equals(other: Any?): Boolean {
        if (other !is Entity) return false
        return id == other.id
    }
    override fun hashCode() = id.hashCode()
}

class User(id: Int, val name: String) : Entity(id)

val user = User(1, "John")
val entity = Entity(1)

user == entity  // true! (по id)

Примеры использования

Поиск в списке:

val users = listOf(
    User("John", 25),
    User("Jane", 30)
)

val john = User("John", 25)
users.contains(john)  // true! Использует equals()

Проверка в условии:

if (currentUser == selectedUser) {
    println("Один и тот же пользователь")
}

Удаление дубликатов:

val allUsers = listOf(
    User("John", 25),
    User("John", 25),  // Дубликат
    User("Jane", 30)
)

allUsers.distinct()  // Удалит дубликат, используя equals()

Правило: equals vs hashCode

Важно: если переопределяешь equals(), ВСЕГДА переопредели hashCode()!

// Плохо — без hashCode
class User(val id: Int) {
    override fun equals(other: Any?) = 
        other is User && id == other.id
    // hashCode() не переопределён!
}

val set = setOf(User(1), User(1), User(1))
println(set.size)  // 3! Ошибка
// Хорошо — с hashCode
class User(val id: Int) {
    override fun equals(other: Any?) = 
        other is User && id == other.id
    override fun hashCode() = id.hashCode()
}

val set = setOf(User(1), User(1), User(1))
println(set.size)  // 1! Правильно

Контракт equals/hashCode

Если a.equals(b) == true, то a.hashCode() == b.hashCode()

  • Это гарантирует правильную работу HashSet, HashMap и др.
  • Нарушение контракта = баги в коллекциях

Вывод

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

  • Используется в коллекциях (List.contains(), Set, Map)
  • Переопредели, если объект имеет "смысл" сравнения
  • Используй data class для автоматического equals()
  • Всегда переопредели hashCode() одновременно
  • В Java это критично, в Kotlin часто автоматизировано
Для чего нужен equals? | PrepBro