чего не предоставляет data class в kotlin

Ключевое слово data

Если у класса указать ключевое слово data, то автоматически будут созданы и переопределены методы toString(), equals(), hashCode(), copy(). Скорее всего вы будете использовать этот вариант для создания полноценного класса-модели с геттерами и сеттерами.

В конструкторе класса у параметров следует указывать val или var.

Подобные классы часто используются при работе с JSON.

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

toString()

Если нужно получить информацию о классе, то достаточно вызвать имя переменной класса. Вы получите строку со всеми значениями всех свойств на основе конструктора вместо непонятных символов @Cat5edea как в Java. Такой подход удобен при тестировании и отладке. Сразу понятно, о чём идёт речь.

Можно сразу определить значение по умолчанию у поля класса. При инициализации объекта можно не указывать поле, но оно будет доступно для вычислений.

equals()

При определении класса данных функция equals() (и оператор ==) по-прежнему возвращает true, если ссылки указывают на один объект. Но она также возвращает true, если объекты имеют одинаковые значения свойств, определённых в конструкторе:

Если вы переопределяете функцию equals(), также необходимо переопределить функцию hashCode().

Кстати, если вам нужно проверить, что две переменные ссылаются на один объект, то используйте оператор ===. В отличие от оператора ==, поведение оператора === не зависит от функции equals(), которое в разных классах может вести себя по разному. Оператор === всегда ведёт себя одинаково независимо от разновидности класса.

hashCode()

Если два объекта данных считаются равными (имеют одинаковые значения свойств), функция hashCode() возвращает для этих объектов одно и то же значение:

Если вам потребуется создать копию объекта данных, изменяя некоторые из его свойств, но оставить другие свойства в исходном состоянии, воспользуйтесь функцией copy(). Для этого функция вызывается для того объекта, который нужно скопировать, и ей передаются имена всех изменяемых свойств с новыми значениями.

Фактически мы создаём копию объекта, меняем значение нужного свойства и присваиваем новый объект переменной с новым именем. При этом исходный объект остаётся без изменений.

Деструктурирующее присваивание

Мы могли бы обратиться и привычным способом.

Деструктуризация позволяет разбить объект на несколько переменных.

Можно пропустить через цикл.

Можно пропустить какую-то переменную через символ подчёркивания.

Несколько конструкторов

Добавить второй конструктор к классу можно через ключевое слово constructor.

Источник

Data classes

It is not unusual to create classes whose main purpose is to hold data. In such classes, some standard functionality and some utility functions are often mechanically derivable from the data. In Kotlin, these are called data classes and are marked with data :

The compiler automatically derives the following members from all properties declared in the primary constructor:

equals() / hashCode() pair

toString() of the form «User(name=John, age=42)»

componentN() functions corresponding to the properties in their order of declaration.

copy() function (see below).

To ensure consistency and meaningful behavior of the generated code, data classes have to fulfill the following requirements:

The primary constructor needs to have at least one parameter.

Data classes cannot be abstract, open, sealed, or inner.

Additionally, the generation of data class members follows these rules with regard to the members’ inheritance:

If a supertype has componentN() functions that are open and return compatible types, the corresponding functions are generated for the data class and override those of the supertype. If the functions of the supertype cannot be overridden due to incompatible signatures or due to their being final, an error is reported.

Providing explicit implementations for the componentN() and copy() functions is not allowed.

Data classes may extend other classes (see Sealed classes for examples).

On the JVM, if the generated class needs to have a parameterless constructor, default values for the properties have to be specified (see Constructors).

Properties declared in the class body

The compiler only uses the properties defined inside the primary constructor for the automatically generated functions. To exclude a property from the generated implementations, declare it inside the class body:

Copying

Use the copy() function to copy an object, allowing you to alter some of its properties while keeping the rest unchanged. The implementation of this function for the User class above would be as follows:

You can then write the following:

Data classes and destructuring declarations

Component functions generated for data classes make it possible to use them in destructuring declarations:

Standard data classes

The standard library provides the Pair and Triple classes. In most cases, though, named data classes are a better design choice because they make the code more readable by providing meaningful names for the properties.

Источник

Класс данных – data class

Нередко в программах требуются объекты, предназначенные во многом для хранения данных. Например, для книг надо описывать их автора, название, год издания и т. д. В более старых языках программирования, таких как Паскаль и Си, для подобных целей существует такой тип данных как «запись». В более современных языках обычно для этих целей используют обычные классы, в которых методов может и не быть. Вот как мог бы выглядеть подобный класс и его объекты на языке Kotlin:

С объектами таких классов данных часто выполняются стандартные действия. Например, вывод значений свойств объекта, создание другого объекта с почти такими же значениями свойств, как у существующего. Поэтому Kotlin идет дальше и вводит в язык особый вариант класса – класс данных. Его объявление начинается со слова data.

Разница между этим вариантом и предыдущем в том, что к таким классам компилятор добавляет методы toString(), equals() и hashCode(), которые переопределяют эти методы, наследуемые по умолчанию всеми классами от Any. В результате в дата-классах эти функции-члены работают по-другому, они адаптированы под задачи, которые выполняют дата-классы. Также компилятор добавляет несколько других функций-членов, например, copy().

Метод toString() data-класса создает строку, содержащую перечень свойств и их значений.

Не забываем, что функция println() сама вызывает toString(). Конечно, мы можем переопределить метод в дата-классе, если нам не нравится его реализация по-умолчанию.

При этом мы переопределяем не тот toString(), который будет добавлен компилятором в связи с модификатором data. Мы переопределяем toString() класса Any. Поэтому если реализация метода toString() будет выглядеть как ниже, то это возврат к тому, что делает Any, несмотря на то, что класс data.

Функция-член equals() (перегружает оператор ==), которую добавляет компилятор к data-классам, сравнивает поля и на этом основании выносит суждение о том, равны ли объекты.

Если бы класс Book был объявлен без модификатора data, то результат обоих сравнений был бы false, потому что переменные a и c указывают на разные объекты. То есть сравнивались бы ссылки на объекты, а не значения полей объекта.

Функция copy() дата-класса, позволяет не просто создавать копию объекта, также на ходу изменять данные при необходимости:

Мультидекларация – это «распаковка» объекта таким образом, что значения его свойств присваиваются сразу нескольким переменным. В случае data-класса это выглядит так:

Чтобы подобное было возможно, компилятор добавляет в дата-класс функции, перегружающие операцию мультидекларации. Обычные классы по-умолчанию не поддерживают такую распаковку, но программист может добавить эту возможность в любой класс. Так бы выглядел обычный класс, но с поддержкой мультидекларации:

Операция мультидекларации также часто используется в цикле for. Если имеется список книг, можно легко пройтись по их свойствам:

Все вышеперечисленные функции по-умолчанию обрабатывают только свойства перечисленные в первичном конструкторе. Однако класс данных может содержать и другие.

В данном случае поле pages будет игнорироваться как при строковом представлении объекта, сравнении объектов, копировании, так и в мультидекларации.

В Котлин есть встроенные дата-классы – Triple и Pair, предназначенные для создания объектов с тремя или двумя свойствами. Тип свойств может быть любым.

Объекты класса Pair нередко используются при обработке коллекций в цикле for.

Источник

Kotlin. Классы данных (Data classes)

Не каждый класс можно отметить ключевым словом data. Для этого он должен соответствовать определённым требованиям:

Переопределяемые функции

toString()

Часто, особенно при отладке, возникает необходимость вывести в лог информацию об экземпляре класса. Если метод toString() не переопределён, то при обращении к экземпляру в лог будет выведена ссылка на него.

Это не очень информативно и вряд ли чем-то поможет. Чтобы исправить ситуацию достаточно переопределить метод toString() и указать в нём, что именно нужно выводить в лог при обращении к экземпляру класса.

Если же мы отметим класс ключевым словом data, метод toString() будет переопределён автоматически. При этом в лог будут выводиться все поля, указанные в конструкторе, в порядке их добавления.

equals()

Иногда нам может потребоваться сравнить между собой два объекта таким образом, чтобы они считались равными, если содержат одни и те же данные.

Если же мы отметим класс ключевым словом data, метод equals() будет переопределён автоматически. При этом работать будет точно также, как и в примере выше: будет проверять на равенство все значения, указанные в основном конструкторе.

hashCode()

Экземпляр класса можно использовать как ключ в структурах данных на основе хэш-функций. Это возможно благодаря тому, что каждому объекту присваивается уникальный хэш-код, даже если значения этих объектов идентичны.

Опять же, чтобы обо всём этом не думать, достаточно отметить класс ключевым словом data и метод hashCode() (и все остальные) будет переопределён автоматически. При этом работать будет точно также, как и в примере выше: будет возвращать значение, зависящее от хэш-кодов всех свойств, объявленных в основном конструкторе.

Ещё один метод, который генерируется автоматически для всех классов данных. Он позволяет копировать экземпляры класса, изменяя значения некоторых свойств.

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

Можно реализовать самостоятельно следующим образом:

Мультидекларации

Стандартные классы данных

Влияние data-классов на вес приложения

Мне встречались споры о том, стоит ли в принципе использовать data-классы в своём приложении. Ведь порой мы хоть и создаём data-класс, но не используем его функциональность, потому что, например, нам нужно просто получить ответ от сервера и передать данные в другое место. И в этом случае выходит так, что все эти автоматически сгенерированные методы впустую занимают место. К тому же, если действительно понадобится любой из вышеперечисленных методов, то его можно самостоятельно реализовать.

И вот перед разработчиками встал вопрос: стоит ли при создании класса задаваться вопросом “а нужен ли мне здесь data-класс”?

Чтобы ответить на этот вопрос, сначала нужно ответить на другой: насколько велико влияние data-классов на вес приложения?

И вот я наткнулась на статью, где автор провёл исследование, чтобы ответить на этот вопрос:
Влияние Kotlin data-классов на вес приложения.

В этой статье автор описал, как он создал плагин для удаления всех автогенерируемых методов с целью сравнить вес приложения с этими методами и без них. Разница составила 4%, подробнее о деталях читайте в статье.

Так каков в результате ответ? Использовать везде или использовать с осторожностью?

Тут всё достаточно просто. При создании класса для хранения данных подумайте для чего он будет использоваться. Понадобится ли функциональность data-класса? Если этот класс нужен только как переходник для данных, то подойдёт и обычный класс.

Хотя на мой взгляд оптимизация в 4% слишком мала, чтобы тратить время на раздумья. Но в любом случае проведённое исследование похвально.

Полезные ссылки

Источник

Влияние Kotlin data-классов на вес приложения

чего не предоставляет data class в kotlin. image loader. чего не предоставляет data class в kotlin фото. чего не предоставляет data class в kotlin-image loader. картинка чего не предоставляет data class в kotlin. картинка image loader. Если у класса указать ключевое слово data, то автоматически будут созданы и переопределены методы toString(), equals(), hashCode(), copy(). Скорее всего вы будете использовать этот вариант для создания полноценного класса-модели с геттерами и сеттерами.

Kotlin имеет много классных особенностей: null safety, smart casts, интерполяция строк и другие. Но одной из самых любимых разработчиками, по моим наблюдениям, являются data-классы. Настолько любимой, что их часто используют даже там, где никакой функциональности data-класса не требуется.

В этой статье я с помощью эксперимента постараюсь понять, какова реальная цена использования большого количества data-классов в приложении. Я попробую удалить все data-классы, не сломав компиляцию, но сломав приложение, а потом расскажу о результатах и выводах этого эксперимента.

Data-классы и их функциональность

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

чего не предоставляет data class в kotlin. qhhezzksl. чего не предоставляет data class в kotlin фото. чего не предоставляет data class в kotlin-qhhezzksl. картинка чего не предоставляет data class в kotlin. картинка qhhezzksl. Если у класса указать ключевое слово data, то автоматически будут созданы и переопределены методы toString(), equals(), hashCode(), copy(). Скорее всего вы будете использовать этот вариант для создания полноценного класса-модели с геттерами и сеттерами.

Но мы платим далеко не за всю эту функциональность. Для релизных сборок используются оптимизаторы R8, ProGuard, DexGuard и другие. Они могут удалять неиспользуемые методы, а значит, могут и оптимизировать data-классы.

Масштаб изменений

Но вручную такое поведение реализовать невозможно. Единственный способ удалить эти функции из кода — переопределить их в следующем виде для каждого data-класса в проекте:

Вручную для 7749 data-классов в проекте.

чего не предоставляет data class в kotlin. vg1asom2iej0yvkkvz5lmz able. чего не предоставляет data class в kotlin фото. чего не предоставляет data class в kotlin-vg1asom2iej0yvkkvz5lmz able. картинка чего не предоставляет data class в kotlin. картинка vg1asom2iej0yvkkvz5lmz able. Если у класса указать ключевое слово data, то автоматически будут созданы и переопределены методы toString(), equals(), hashCode(), copy(). Скорее всего вы будете использовать этот вариант для создания полноценного класса-модели с геттерами и сеттерами.

Ситуацию усугубляет использование монорепозитория для приложений. Это означает, что я не знаю точно, сколько из этих 7749 классов мне нужно изменить, чтобы измерить влияние data-классов только на одно приложение. Поэтому придётся менять все!

Плагин компилятора

Вручную такой объём изменений сделать невозможно, поэтому самое время вспомнить о такой прекрасной незадокументированной вещи, как плагины компилятора. Мы уже рассказывали про наш опыт создания плагина компилятора в статье «Чиним сериализацию объектов в Kotlin раз и навсегда». Но там мы генерировали новые методы, а здесь нам нужно их удалять.

В открытом доступе на GitHub есть плагин Sekret, который позволяет скрывать в toString() указанные аннотацией поля в data-классах. Его я и взял за основу своего плагина.

С точки зрения создания структуры проекта практически ничего не поменялось. Нам понадобятся:

ClassBuilderInterceptorExtension позволяет изменять процесс генерации классов, а значит, с его помощью мы сможем избежать создания ненужных методов.

Весь код доступен в репозитории, там же есть пример интеграции плагина.

Результаты

чего не предоставляет data class в kotlin. image loader. чего не предоставляет data class в kotlin фото. чего не предоставляет data class в kotlin-image loader. картинка чего не предоставляет data class в kotlin. картинка image loader. Если у класса указать ключевое слово data, то автоматически будут созданы и переопределены методы toString(), equals(), hashCode(), copy(). Скорее всего вы будете использовать этот вариант для создания полноценного класса-модели с геттерами и сеттерами.

Для сравнения мы будем использовать релизные сборки Bumble и Badoo. Результаты были получены с помощью утилиты Diffuse, которая выводит детальную информацию о разнице между двумя APK-файлами: размеры DEX-файлов и ресурсов, количество строк, методов, классов в DEX-файле.

ПриложениеBumbleBumble (после)РазницаBadooBadoo (после)Разница
Data-классы40262894
Размер DEX (zipped)12.4 MiB11.9 MiB-510.1 KiB15.3 MiB14.9 MiB-454.1 KiB
Размер DEX (unzipped)31.7 MiB30 MiB-1.6 MiB38.9 MiB37.6 MiB-1.4 MiB
Строки в DEX188969179197-9772244116232114-12002
Методы292465277475-14990354218341779-12439

Количество data-классов было определено эвристическим путём с помощью анализа удалённых из DEX-файла строк.

чего не предоставляет data class в kotlin. image loader. чего не предоставляет data class в kotlin фото. чего не предоставляет data class в kotlin-image loader. картинка чего не предоставляет data class в kotlin. картинка image loader. Если у класса указать ключевое слово data, то автоматически будут созданы и переопределены методы toString(), equals(), hashCode(), copy(). Скорее всего вы будете использовать этот вариант для создания полноценного класса-модели с геттерами и сеттерами.

Реализация toString() у data-классов всегда начинается с короткого имени класса, открывающей скобки и первого поля data-класса. Data-классов без полей не существует.

Исходя из результатов, можно сказать, что в среднем каждый data-класс обходится в 120 байт в сжатом и 400 байт — в несжатом виде. На первый взгляд, не много, поэтому я решил проверить, сколько получается в масштабе целого приложения. Выяснилось, что все data-классы в проекте обходятся нам в

4% размера DEX-файла.

Также стоит уточнить, что из-за MVI-архитектуры мы можем использовать больше data-классов, чем приложения на других архитектурах, а значит, их влияние на ваше приложение может быть меньше.

Использование data-классов

Я ни в коем случае не призываю вас отказываться от data-классов, но, принимая решение об их использовании, нужно тщательно всё взвесить. Вот несколько вопросов, которые стоит задать себе перед объявлением data-класса:

Мы не можем совсем отказаться от использования data-классов в проекте, и приведённый выше плагин ломает работоспособность приложения. Удаление методов было сделано ради оценки влияния большого количества data-классов. В нашем случае это

4% от размера DEX-файла приложения.

Если вы хотите оценить, сколько места занимают data-классы в вашем приложении, то можете сделать это самостоятельно с помощью моего плагина.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *