data class и object

Знакомимся с классами данных и объектами-одиночками.

data class — особый вид класса для хранения данных, для которого компилятор сам генерирует equals, hashCode, toString и copy.

Очень часто класс нужен лишь для того, чтобы хранить набор полей. Для таких случаев Kotlin предлагает data class — он избавляет от рутины, генерируя полезные методы автоматически.

data class

Достаточно добавить ключевое слово data — и вы получаете осмысленный toString, сравнение по содержимому через == и метод copy.

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

fun main() {
    val a = User("Аня", 25)
    val b = User("Аня", 25)
    println(a)          // понятный toString
    println(a == b)     // сравнение по содержимому
}

Вывод:

User(name=Аня, age=25)
true

Метод copy

copy создаёт копию объекта, позволяя изменить отдельные поля. Это удобно для неизменяемых данных: вместо мутации создаём новый объект.

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

fun main() {
    val a = User("Аня", 25)
    val older = a.copy(age = 26)
    println(a)
    println(older)
}

Вывод:

User(name=Аня, age=25)
User(name=Аня, age=26)

object — объект-одиночка

Ключевое слово object создаёт синглтон — единственный экземпляр на всю программу. Удобно для конфигурации или утилит без состояния.

object Config {
    val appName = "CodeChick"
    fun describe() = "Приложение: $appName"
}

fun main() {
    println(Config.describe())
}

Вывод:

Приложение: CodeChick

companion object

В Kotlin нет статических членов, как в Java. Их роль играет companion object — объект, привязанный к классу; обращаются к нему через имя класса.

class User(val name: String) {
    companion object {
        fun guest() = User("Гость")
    }
}

fun main() {
    val u = User.guest()
    println(u.name)
}

Вывод:

Гость

Как работает под капотом

Для data class компилятор генерирует equals/hashCode на основе свойств, объявленных в первичном конструкторе (свойства из тела класса в них не участвуют). Поэтому два объекта с одинаковыми полями конструктора равны. object же создаётся лениво при первом обращении и существует в единственном экземпляре — это потокобезопасная реализация паттерна Singleton прямо в языке.

Частые ошибки

  • Писать обычный класс там, где нужен data class. Без data придётся вручную писать equals, toString и copy.
  • Искать static. Его в Kotlin нет — используйте companion object или функции верхнего уровня.
  • Ждать, что поля из тела класса попадут в equals. В equals участвуют только свойства первичного конструктора.

Итог

  • data class автоматически даёт equals, hashCode, toString и copy.
  • copy создаёт изменённую копию объекта.
  • object — синглтон, единственный экземпляр на программу.
  • companion object заменяет статические члены Java.
Проверьте себя
1. Что генерирует компилятор для data class автоматически?
AТолько конструктор
Bequals, hashCode, toString и copy
CГрафический интерфейс
DБазу данных
2. Что делает ключевое слово object перед именем?
AСоздаёт обычный класс
BСоздаёт синглтон — единственный экземпляр
CСоздаёт интерфейс
DСоздаёт data class
3. Чем в Kotlin заменяют статические члены из Java?
AКлючевым словом static
Bcompanion object
CКлючевым словом data
DБлоком init