Как работают final и static в Kotlin и Java
Что проверяют
Понимаете ли вы, что в двух языках один и тот же смысл выражен по-разному, и как Kotlin-код выглядит со стороны Java. Следом обычно спрашивают, зачем нужен @JvmStatic, чем const val отличается от val в companion object, или почему статическая ссылка на Activity опасна.
Как отвечать
final в Java работает на трёх уровнях:
- переменная и поле: присвоить можно один раз. Для ссылки запрещено переприсвоение, но сам объект менять можно;
- метод: нельзя переопределить;
- класс: нельзя наследовать, как
String.
У final-полей есть ещё гарантия модели памяти: другой поток увидит значения, выставленные в конструкторе, если ссылка на объект не утекла раньше времени.
В Kotlin всё наоборот: классы и методы закрыты по умолчанию, наследование и переопределение открывает open. Явный final пишут в одном случае: final override fun, чтобы запретить дальнейшее переопределение. Аналог final-переменной это val.
Слова static в Kotlin нет, вместо него несколько механизмов:
- функции и свойства верхнего уровня: компилируются в статические члены класса
ИмяФайлаKt; object: синглтон;companion object: объект внутри класса. Из Java его члены видны какMyClass.Companion.foo(), пока не добавить@JvmStaticили@JvmField;const val: константа времени компиляции, только примитивы иString, значение подставляется в место использования.
Для Android важен побочный эффект: статическое поле живёт столько же, сколько процесс. Ссылка на Activity или View в нём удерживает весь экран после onDestroy, такие утечки ловит LeakCanary. Если контекст нужен надолго, берут applicationContext.
Где спотыкаются
Считают, что final делает объект неизменяемым. В final List можно добавлять элементы, неизменяемость дают только сам тип и его реализация.
Приравнивают companion object к static. Это настоящий объект, и без @JvmStatic Java-код обращается к нему через Companion.
Думают, что закрытые по умолчанию классы ломают моки. Mockito с пятой версии по умолчанию использует inline mock maker и мокает final-классы, а MockK справлялся с этим всегда.