Какие типы данных относятся к мутабельным, а какие к немутируемым
Что проверяют
Понимаете ли вы разницу между неизменяемым объектом, неизменяемой ссылкой и коллекцией «только для чтения». На Android это не теория: от неё зависит, увидит ли экран новое состояние. Следом обычно спрашивают, чем val отличается от неизменяемости и почему StateFlow молчит после list.add().
Как отвечать
Разведите три уровня:
- неизменяемые объекты:
String, обёрткиInteger,Longи остальные,BigDecimal,LocalDateизjava.time, Kotlindata class, у которого все поляvalи сами неизменяемы. Любое «изменение» создаёт новый объект; - изменяемые объекты:
ArrayList,HashMap,StringBuilder, массивы,MutableList, классы с полямиvar; - ссылка против объекта:
valзапрещает переприсвоить переменную, но не менять объект.val list = mutableListOf(1)спокойно принимаетlist.add(2).
Отдельно про коллекции Kotlin. List это интерфейс только для чтения, а не гарантия неизменяемости: за ним может стоять ArrayList, который кто-то меняет через ссылку MutableList. В Java так же ведёт себя Collections.unmodifiableList(): это обёртка, и изменения исходного списка через неё видны. По-настоящему неизменяемые коллекции дают List.of() в Java и persistentListOf() из kotlinx.collections.immutable.
Зачем это на Android: неизменяемое состояние безопасно передавать между потоками и корутинами, а StateFlow и Compose сравнивают старое и новое значение. Рабочий паттерн: _state.update { it.copy(items = it.items + item) }, то есть новый объект вместо правки старого.
Где спотыкаются
Говорят, что val делает объект неизменяемым. Это только про ссылку, внутренности такого объекта меняются свободно.
Меняют список внутри состояния на месте и присваивают ту же ссылку. StateFlow сравнивает значения через equals, видит тот же объект и ничего не эмитит, экран не обновляется.
Приводят Integer num = 5; num = 10; как пример неизменяемости. Здесь меняется переменная, а не объект, и к тому же маленькие значения берутся из кэша Integer, новый объект не создаётся.