jvm 为什么我们不能在不初始化瓦尔属性的情况下用get将其作为var覆盖呢?

csga3l58  于 2022-11-07  发布在  其他
关注(0)|答案(3)|浏览(144)

我刚开始学习Kotlin。我想知道为什么我们不能在不初始化的情况下将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}")
}

如果我没有在Bar类中初始化x,它会给出一个编译器错误Property must be initialised。但是当我打印bar.x时,它会打印从被覆盖的getter计算的值,而不是从初始化的getter计算的值。

vngu2lb8

vngu2lb81#

如果没有以某种方式定义两个访问器(getset),则无法定义var属性。
当你放置一个初始化器(var x: Int = ...)时,会生成一个支持字段和一个设置支持字段的默认setter。一个替代初始化器的方法是提供一个自定义setter:

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

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

ix0qys7i

ix0qys7i2#

这种行为是由于Kotlin中支持字段的概念。
如果属性使用至少一个存取子的预设实作,或如果自订存取子透过字段识别项指涉它,则会产生属性的支援字段。
由于被覆盖的属性x现在是一个var,因此它有一个setter的默认实现,如下所示。

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

因此,当声明一个var时,你必须用某个值初始化支持字段,因为在Kotlin中没有默认值的概念(例如,未初始化的Java对象取空值)。
另一个解决方案是使用这样的自定义setter-

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

z2acfund3#

open class Parent {
    open var x: Int = 0
}

class Child : Parent() {
    override val x = 2
}

转换为java

public class Parent {
   private int x;

   public int getX() {
      return this.x;
   }

   public void setX(int var1) {
      this.x = var1;
   }
}

public final class Child extends Parent {
   private final int x = 2;

   public int getX() {
      return this.x;
   }
}

因此瓦尔属性未创建setter

相关问题