Можно ли изменить переменную типа val в Kotlin
Что проверяют
Понимаете ли вы разницу между неизменяемой ссылкой и неизменяемым объектом. Следом почти всегда спрашивают: «Может ли val вернуть разное значение при двух обращениях?» и «Чем val отличается от const val?»
Как отвечать
Короткий ответ: переприсвоить val нельзя, строку x = 5 компилятор не пропустит. Но «нельзя переприсвоить» и «значение никогда не меняется» это разные утверждения, и сильный ответ показывает, где они расходятся:
- изменяемый объект за ссылкой:
val list = mutableListOf(1)не мешает вызватьlist.add(2). Неизменна ссылка, а не содержимое. Настоящую неизменяемость даютListвместоMutableList, data class сval-полями иcopy(); - кастомный геттер:
val now: Long get() = System.currentTimeMillis()возвращает новое значение при каждом чтении. Для вызывающего этоval, хранимого значения у него нет; - делегаты:
val user by lazy { ... }вычисляется при первом обращении, аval state by viewModel.uiState.collectAsState()в Compose меняется при каждой эмиссии; - переопределение:
open valв базовом классе можно переопределить какoverride varв наследнике, обратное запрещено; - const val: константа времени компиляции, только примитивы и
String, только на верхнем уровне, вobjectилиcompanion object. Значение подставляется прямо в место вызова.
Добавьте, почему val предпочтительнее: для локальных val и для свойств без кастомного геттера в пределах модуля работает smart cast, а с var компилятор часто отказывается, потому что значение могло поменяться между проверкой и использованием.
Где спотыкаются
Говорят «val это как final в Java, значит объект неизменяемый». Сравнение с final честное только для ссылки, про сам объект оно ничего не говорит.
Путают val с потокобезопасностью. Неизменная ссылка на MutableList, который правят из двух корутин, остаётся гонкой данных.
Приводят рефлексию как нормальный способ «поменять val». Поле иногда удаётся перезаписать через Field.setAccessible, но это хак, который не работает для const и заинлайненных значений, и как ответ на вопрос он не годится.