Классы данных

Классы данных #

Васильев Андрей Михайлович, 2024

Версии презентации


Создание классов данных #

Нередко мы создаём классы, единственным назначением которых является хранение данных

Функционал и некоторые служебные функции таких классов зависят от самих данных, которые в них хранятся. В Kotlin они называются классами данных и помечены data

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

Автоматически генерируемые части #

Компилятор автоматически формирует следующие члены данного класса из свойств, объявленных в основном конструкторе:

  • пару функций equals() и hashCode()
    • объекты будут сравниваться по значению полей
    • уникальность объектов основывается на значениях, а не идентификаторе
  • функцию toString() в форме "User(name=John, age=42)"
  • компонентные функции componentN(), которые соответствуют свойствам, в соответствии с порядком их объявления
  • функцию copy(), которая будет рассмотрена далее

Требования к классам данных #

Для обеспечения согласованности и осмысленного поведения сгенерированного кода классы данных должны удовлетворять следующим требованиям:

  • Основной конструктор должен иметь как минимум один параметр
  • Все параметры основного конструктора должны быть отмечены, как val или var
  • Классы данных не могут быть абстрактными, open, sealed или inner
  • Классы данных могут наследовать другие классы и реализовывать интерфейсы

Свойства, объявленные в теле класса #

Компилятор использует только свойства, определенные в основном конструкторе для автоматически созданных функций. Чтобы исключить свойство из автоматически созданной реализации, объявите его в теле класса:

data class Person(val name: String) {
    var age: Int = 0
}

Только свойство name будет учитываться в реализациях функций toString(), equals(), hashCode() и copy(), и будет создана только одна компонентная функция component1(). Даже если два объекта класса Person будут иметь разные значения свойств age, они будут считаться равными.

val person1 = Person("John")
val person2 = Person("John")
person1.age = 10
person2.age = 20

Классы данных и мульти-декларации #

Сгенерированные для классов данных компонентные функции позволяют использовать их в мульти-декларациях

val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // выводит "Jane, 35 years of age"

Копирование #

Используйте функцию 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() классы данных позволяют простым образом обрабатывать данные внутри приложения. Каждое новое состояние записывается в отдельный объект

  • Как это происходит с числами
  • Как это происходит со строками в Java
val initial = User(
    name = "Василий",
    age = 5,
)
val daysPassed = initial.copy(
    age = 55,
)

diagram

Чем больше полей в классе данных, тем эффективнее операция копирования при записи

© A. M. Васильев, 2024, CC BY-SA 4.0, andrey@crafted.su