为什么 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 不相同的值,它将不会正确运行的文档。
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 上的一个单独函数,只是通过调整 属性 定义(以定义的、受限的方式)
来方便地表达
即使在接口或抽象 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 不相同的值,它将不会正确运行的文档。
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 mutablevar
);- 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 上的一个单独函数,只是通过调整 属性 定义(以定义的、受限的方式)