Есть ли проблемы при передаче массива вместо списка в дата класс Kotlin
Что проверяют
Знаете ли вы, что data class генерирует equals(), hashCode() и toString() по свойствам первичного конструктора, и что с массивом это ломается. Следом обычно спрашивают, как проблема проявится в ListAdapter или StateFlow.
Как отвечать
Корень проблемы: массивы на JVM не переопределяют equals() и hashCode(), сравнение идёт по ссылке. Поэтому:
- равенство:
User("a", intArrayOf(1)) == User("a", intArrayOf(1))вернётfalse, хотя содержимое одинаковое. IDE прямо предупреждает об этом на свойстве-массиве в data-классе; hashCode(): зависит от ссылки, и такой объект вHashSetили ключомHashMapведёт себя непредсказуемо;toString(): в логах вместо данных увидите что-то вроде[I@1b6d3586;- изменяемость: массив можно поменять на месте, а
copy()копирует поверхностно, и копия делит с оригиналом тот же массив.
На Android это даёт конкретные баги. DiffUtil.ItemCallback.areContentsTheSame() через == считает одинаковые элементы разными и перерисовывает их при каждом обновлении. StateFlow пропускает значение, равное текущему: если поменять массив на месте и выставить state.copy(), новое состояние окажется «равным» старому, и экран не обновится.
Решения: взять List<T>, который сравнивается по содержимому, или переопределить equals() и hashCode() через contentEquals() и contentHashCode(). Массив оправдан там, где важна производительность: IntArray и FloatArray хранят примитивы без упаковки.
Где спотыкаются
Говорят, что List неизменяемый. Это интерфейс только для чтения: под ним может лежать ArrayList, который кто-то меняет через ссылку на MutableList. Настоящую неизменяемость дают коллекции из kotlinx.collections.immutable.
Переопределяют equals(), но забывают hashCode(), и объект перестаёт находиться в HashSet и HashMap.
Считают, что copy() делает глубокую копию. Вложенные массивы и изменяемые коллекции остаются общими для оригинала и копии.