为什么 super class 的不可变性没有被强加到 child class 中?

Why immutability of super class is not forced in child class?

即使在接口或抽象 class.

中使用 val 声明不可变字段,您也可以破坏 super class 的不可变性
interface Foo {
    val bar: String // immutable
}

class FooImpl : Foo {
    override var bar: String = "bar" // mutable

    init {
        bar = "changed"
    }
}

println(FooImpl().bar) // changed

我预计上面的代码会出现编译错误,但它有效。 为什么这在 kotlin 中可行?

val 并不意味着 不可变 。意思是read-only。即使您不将其重写为 var,您也可以将其设为 val,每次 return 都是不同的值。

因此将其扩展为可写并没有违反任何约定。

无法强制打开 属性 不可变。您能做的最好的事情就是使用声明如果它每次都return 不相同的值,它将不会正确运行的文档。

来自language spec:

A property declaration D which overrides property declaration B should satisfy the following conditions.

  • Mutability of D is not stronger than mutability of B (where read-only val is stronger than mutable var);
  • Type of D is a subtype of type of B ; except for the case when both D and B are mutable (var), then types of D and B must be equivalent.

因此您的重写 属性 可以增加可变性,并且还可以使用更具体的子类型(例如 Int 而不是 Number 只要 声明不是 var(因此您不能通过接口向其写入 Double)。

您可以查看它的一种方式是,您的原始 val 有点像声明您要覆盖的 getBar(): String 函数。通过将其设为 var,您还在自己的 class.

中定义了 setString(string) 函数

如果您尝试访问您的对象 as Foo,那么 setter 不存在,因为它没有(隐含地)在接口中定义。它是 class 上的一个单独函数,只是通过调整 属性 定义(以定义的、受限的方式)

来方便地表达