为什么我们不能用一个get来重写一个val属性,而不用初始化呢?

我刚刚开始学习Kotlin。 我想知道为什么我们无法将重写的val属性的get()方法用作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) { val bar: Bar = Bar() println("${bar.x}") } 

如果我不初始化Bar类中的x ,它会给出编译器错误Property must be initialised 。 但是,当我打印bar.x打印从重写的getter计算的值,但不是从初始化的。

这种行为是由于Kotlin中支持字段的概念。 正如在doc中写的 –

如果属性使用至少一个访问器的默认实现,或者自定义访问器通过字段标识符引用它,则会为属性生成后台字段。

由于重写的属性x现在是一个var,它具有如下所示的setter的默认实现。

 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 } 

如果没有以某种方式定义访问器( getset ),则无法定义var属性。

当你把一个初始化程序( var x: Int = ... )时,会生成一个后台字段,并设置一个默认的setter来设置后台字段。 初始化程序的一个替代方案是提供一个自定义设置程序:

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

请参阅:语言参考中的属性和字段