Выбор ответа Senior Null-safety обновлено

NPE при вызове открытого метода из конструктора

Вопрос

Почему этот код упадёт с NullPointerException, хотя name объявлен как String?

open class Base {
    init { describe() }
    open fun describe() {}
}

class Child(val name: String) : Base() {
    override fun describe() { println(name.length) }
}

fun main() { Child("Kotlin") }

Попробуйте сами

Выберите вариант, и откроется разбор.

Показать ответ и разбор

Коротко

Правильный ответ: init базы вызывает describe() до инициализации name. Порядок инициализации: сначала отрабатывает конструктор и init базового класса, потом поля наследника.

Варианты ответа

  1. println не умеет печатать Int без toString()
  2. init базы вызывает describe() до инициализации nameправильный ответ
  3. Kotlin не проверяет non-null типы в рантайме совсем
  4. override fun нельзя вызывать из init базового класса

Разбор

Порядок инициализации: сначала отрабатывает конструктор и init базового класса, потом поля наследника. Открытый метод, вызванный из init базы, уходит в реализацию наследника, где name ещё не присвоен, а на JVM это null. name.length бросит NPE. Компилятор предупреждает о вызове открытого члена из конструктора. Kotlin проверяет null в рантайме на границах (например, параметры публичных функций), но не здесь.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.