Будут ли равны ссылки у двух одинаковых объектов после копирования в Kotlin
Что проверяют
Различаете ли вы структурное и ссылочное равенство и понимаете ли, что на самом деле делает copy() у data class. Следом почти всегда спрашивают про вложенные объекты: что станет с изменяемым списком внутри копии.
Как отвечать
В Kotlin два оператора сравнения:
==: структурное равенство, вызовequals()с проверкой наnull. Уdata classequals()генерируется по свойствам первичного конструктора;===: ссылочное равенство, один ли это объект в памяти.
Отсюда ответ: val b = a.copy() создаёт новый экземпляр, поэтому a === b даёт false, а a == b даёт true. Присваивание val b = a ничего не копирует, это вторая ссылка на тот же объект, и a === b будет true.
Дальше главная деталь: copy() поверхностный. Поля переносятся по ссылке, и если внутри лежит MutableList или другой изменяемый объект, у оригинала и копии он общий: a.items === b.items даёт true, а изменение через копию видно в оригинале. Для глубокой копии вложенное копируют вручную, например copy(items = items.toMutableList()), но лучше сразу делать модель неизменяемой.
Свойства, объявленные в теле класса, а не в конструкторе, в equals(), hashCode() и copy() не участвуют: копия получит для них значения по умолчанию.
Для Android это не теория. StateFlow не эмитит новое значение, если оно равно предыдущему по equals(), mutableStateOf в Compose по умолчанию сравнивает так же, а DiffUtil обычно проверяет содержимое через тот же equals(). Поэтому состояние экрана обновляют через state.copy(...) с неизменяемыми полями.
Где спотыкаются
Считают copy() глубоким копированием и мутируют вложенный список копии, незаметно ломая оригинал.
Переносят привычки из Java: там == сравнивает ссылки, а в Kotlin это equals(). Кандидаты, пришедшие с Java, иногда описывают операторы ровно наоборот.
Меняют список внутри текущего объекта состояния и присваивают StateFlow тот же объект. Ссылка та же, equals() вернул true, эмиссии нет, и экран не перерисовывается.