为什么我们不能将val属性覆盖为带有get而没有初始化的var?

时间:2017-12-29 13:54:55

标签: jvm kotlin

我刚刚开始学习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<String>) {
    val bar: Bar = Bar()
    println("${bar.x}")
}

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

2 个答案:

答案 0 :(得分:4)

如果没有以某种方式定义的访问者(varget),则无法定义set属性。

放置初始值设定项(var x: Int = ...)时,会生成一个支持字段,并设置一个默认设置器来设置支持字段。初始化程序的替代方法是提供自定义setter:

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

请参阅语言参考中的Properties and Fields

答案 1 :(得分:3)

这种行为归因于Kotlin中backing fields的概念。正如文档中所写 -

  

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

由于重写的属性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
            }