Почему мы не можем переопределить свойство val как var с get без его инициализации?

Я только начал изучать Котлина. Интересно, почему мы не можем использовать метод get() для переопределенного свойства val как var без его инициализации. Но когда он переопределяется как val он работает без инициализации.

 open class Foo { val y = 21 open val x: Int get() { return 10 * y } } class Bar : Foo() { override var x: Int = super.x * 10 //If overridden as val works without initialisation get() { return super.x * (super.x * 10) } } fun main(args: Array<String>) { val bar: Bar = Bar() println("${bar.x}") } 

Если я не инициализирую x в классе Bar он дает ошибку компилятора. Property must be initialised . Но когда я печатаю bar.x он печатает значение, вычисленное из переопределенного геттера, но не из инициализированного.

Такое поведение связано с концепцией опорных полей в Котлине. Как написано в документе –

Для свойства будет создано поле поддержки, если оно использует реализацию по умолчанию, по крайней мере, одного из аксессуаров, или если пользовательский аксессор ссылается на него через идентификатор поля.

Поскольку переопределенное свойство x теперь является var, оно имеет стандартную реализацию сеттера, как показано ниже.

 override var x: Int = super.x * 10 get() { return super.x * (super.x * 10) } set(value) { field = value } 

Поэтому при объявлении var вы должны инициализировать поле поддержки некоторым значением, поскольку в Kotlin нет концепции значений по умолчанию (например, неинициализированные объекты Java принимают нулевое значение).

Другим решением является использование настраиваемого устройства, например:

 override var x: Int // Now you can leave it uninitialized get() { return super.x * (super.x * 10) } set(value) { // Nothing happens } 

Вы не можете определить свойство var без каких-либо атрибутов доступа ( get и set ).

Когда вы помещаете инициализатор ( var x: Int = ... ), создается фоновое поле и установщик по умолчанию, который устанавливает поле поддержки. Альтернативой инициализатору является создание настраиваемого сеттера:

 override var x: Int get() = super.x * (super.x * 10) set(value) { super.x = sqrt(value / 10.0).roundToInt() } 

См. « Свойства и поля» в справочной системе