Что изменится, если объявить дата класс обычным классом в Kotlin
Что проверяют
Знаете ли вы, что именно компилятор генерирует для data class, и понимаете ли последствия потери этого кода. В Android-проекте они заметны сразу: сравнение моделей лежит в основе обновления списков и в конфлации потоков состояния.
Как отвечать
Модификатор data даёт четыре вещи: equals, hashCode, toString и copy, плюс функции component1, component2 для деструктуризации. Строятся они только по свойствам первичного конструктора.
Убираем data и получаем обычный класс: equals становится сравнением ссылок, hashCode привязывается к объекту, toString печатает имя класса и адрес, copy и деструктуризации нет вовсе. Свойства в конструкторе при этом остаются, val и var там объявлять никто не запрещал.
Дальше про то, что сломается в приложении:
DiffUtilв списке решает черезequals, изменилось ли содержимое. Со ссылочным сравнением каждый элемент считается новым, и список перерисовывается целиком, теряя позицию прокрутки;StateFlowне публикует значение, равное предыдущему. Без сгенерированногоequalsравных значений не бывает, и подписчики получают поток одинаковых обновлений;- объект перестаёт находиться в
HashSetи в качестве ключаHashMap, потому что равный по содержимому экземпляр даёт другойhashCode.
Полезно добавить границы: data class нельзя объявить open или abstract, поэтому наследовать от него нельзя, а сам он вполне может расширять другой класс.
Где спотыкаются
Утверждают, что в обычном классе свойства нельзя объявить прямо в конструкторе. Можно, синтаксис ровно тот же, теряются только сгенерированные функции.
Забывают, что equals и hashCode собираются по первичному конструктору. Свойство, объявленное в теле класса, в сравнении не участвует, и два объекта с разным состоянием считаются одинаковыми.
Переопределяют вручную equals и не трогают hashCode. Контракт нарушен, объект кладут в множество и не находят там, а ошибка всплывает далеко от места правки.