В чем разница между сравнением по ссылке и по значению
Что проверяют
Знаете ли вы, что именно сравнивает == в Kotlin и в Java, и понимаете ли, где это всплывает в Android-коде. Следом обычно просят рассказать про контракт equals/hashCode или объяснить, почему список в RecyclerView не обновился.
Как отвечать
Разведите два вида равенства и два языка:
- структурное равенство: объекты одинаковы по содержимому. В Kotlin это
==, который компилируется в null-безопасный вызовequals(); в Java нужно явно зватьequals()илиObjects.equals(a, b); - ссылочное равенство: это один и тот же объект в памяти. В Kotlin это
===, в Java оператор==для объектов; - примитивы: в Java
==наintсравнивает значения, в KotlinIntбез?компилируется в примитив, и==тоже сравнивает значения.
Потом объясните, откуда берётся equals(). По умолчанию Object.equals сравнивает ссылки, поэтому обычный класс без переопределения равен только самому себе. data class генерирует equals, hashCode и toString по свойствам основного конструктора. Переопределили equals, значит обязаны переопределить и hashCode, иначе объект потеряется в HashMap и HashSet.
Сильный ответ привязан к Android. DiffUtil.ItemCallback делит вопрос на два: areItemsTheSame сравнивает идентификаторы, areContentsTheSame содержимое через equals. StateFlow не эмитит значение, равное текущему по equals, а Compose пропускает рекомпозицию, если стабильные параметры не изменились.
Где спотыкаются
Сравнивают обёртки по ссылке. В Java Integer кэшируется в диапазоне от -128 до 127, поэтому == на 127 даёт true, а на 128 уже false. В Kotlin та же ловушка с === на Int?.
Меняют список на месте и кладут ту же ссылку обратно в MutableStateFlow. Новое значение равно старому, эмита нет, экран не обновляется.
Забывают, что массивы не переопределяют equals: arrayOf(1) == arrayOf(1) в Kotlin даёт false, нужен contentEquals. И что свойства, объявленные в теле data class, в сравнении не участвуют.