Классы данных
Классы данных в Kotlin в первую очередь предназначены для хранения данных. Для каждого класса данных компилятор автоматически генерирует дополнительные функции-члены, которые позволяют выводить экземпляр в удобочитаемом виде, сравнивать экземпляры, копировать их и выполнять другие операции. Классы данных помечаются data:
data class User(val name: String, val age: Int)
Компилятор автоматически генерирует следующие члены на основе всех свойств, объявленных в первичном конструкторе:
пару
equals()/hashCode().toString()вида"User(name=John, age=42)".Функции
componentN(), соответствующие свойствам в порядке их объявления.
Чтобы обеспечить согласованность и предсказуемое поведение сгенерированного кода, классы данных должны удовлетворять следующим требованиям:
Первичный конструктор должен иметь как минимум один параметр.
Все параметры первичного конструктора должны быть помечены как
valилиvar.Классы данных не могут быть абстрактными, открытыми, запечатанными или внутренними.
Кроме того, при генерации членов класса данных применяются следующие правила наследования:
Если в теле класса данных есть явные реализации
equals(),hashCode()илиtoString()либо в суперклассе есть реализацииfinal, эти функции не генерируются и используются существующие реализации.Если у супертипа есть функции
componentN(), которые являютсяopenи возвращают совместимые типы, для класса данных генерируются соответствующие функции, переопределяющие функции супертипа. Если функции супертипа нельзя переопределить из-за несовместимых сигнатур или потому, что они являются final, возникает ошибка.Явные реализации функций
componentN()иcopy()не допускаются.
Классы данных могут наследоваться от других классов (примеры см. в разделе Запечатанные классы).
Свойства, объявленные в теле класса
Для автоматически генерируемых функций компилятор использует только свойства, определённые в первичном конструкторе. Чтобы исключить свойство из сгенерированных реализаций, объявите его в теле класса:
data class Person(val name: String) {
var age: Int = 0
}
В примере ниже по умолчанию в реализациях toString(), equals(), hashCode() и copy() используется только свойство name, а функция-компонент всего одна — component1(). Свойство age объявлено в теле класса и не учитывается. Поэтому два объекта Person с одинаковым значением name, но разными значениями age считаются равными, поскольку equals() учитывает только свойства первичного конструктора:
data class Person(val name: String) {
var age: Int = 0
}
fun main() {
//sampleStart
val person1 = Person("John")
val person2 = Person("John")
person1.age = 10
person2.age = 20
println("person1 == person2: ${person1 == person2}")
// person1 == person2: true
println("person1 with age ${person1.age}: ${person1}")
// person1 with age 10: Person(name=John)
println("person2 with age ${person2.age}: ${person2}")
// person2 with age 20: Person(name=John)
//sampleEnd
}
Копирование
Используйте функцию copy(), чтобы скопировать объект, изменив некоторые его свойства и оставив остальные без изменений. Реализация этой функции для приведённого выше класса User выглядела бы так:
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
Затем можно написать следующее:
val jack = User(name = "Jack", age = 1) val olderJack = jack.copy(age = 2)
Функция copy() создаёт поверхностную копию экземпляра. Иными словами, она не копирует компоненты рекурсивно. В результате ссылки на другие объекты остаются общими.
Например, если свойство содержит изменяемый список, изменения, внесённые через «исходное» значение, также видны через копию, а изменения, внесённые через копию, видны в исходном объекте:
data class Employee(val name: String, val roles: MutableList<String>)
fun main() {
val original = Employee("Jamie", mutableListOf("developer"))
val duplicate = original.copy()
duplicate.roles.add("team lead")
println(original)
// Employee(name=Jamie, roles=[developer, team lead])
println(duplicate)
// Employee(name=Jamie, roles=[developer, team lead])
}
Как видно, изменение свойства duplicate.roles также меняет свойство original.roles, поскольку оба свойства содержат ссылку на один и тот же список.
Классы данных и объявления деструктуризации
Функции-компоненты, генерируемые для классов данных, позволяют использовать их в объявлениях деструктуризации:
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age")
// Jane, 35 years of age
Стандартные классы данных
Стандартная библиотека предоставляет классы Pair и Triple. Однако в большинстве случаев лучше использовать именованные классы данных: благодаря осмысленным названиям свойств код становится понятнее.
© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/data-classes.html