Inheritance 错误或功能:Kotlin允许更改';val';至';var';继承
我刚开始探索科特林的语言。我正在与继承、var&val和副作用作斗争 如果我在Inheritance 错误或功能:Kotlin允许更改';val';至';var';继承,inheritance,side-effects,kotlin,Inheritance,Side Effects,Kotlin,我刚开始探索科特林的语言。我正在与继承、var&val和副作用作斗争 如果我在AImpl中用valx声明特征a,并覆盖x,则可以将其覆盖为var(参见下面的代码)。令人惊讶的是,A中的print()方法受x重新分配的影响,即使x是A中的值。这是一个bug还是一个特性 代码: 但正如第一个案例所显示的,继承可能会导致副作用,而这显然不是A中的意图。如何保护值不被继承更改?您可以将val设置为final,即完全禁止覆盖它。 如果在类中定义val,默认情况下它是final 此外,如果需要使用var覆盖
AImpl
中用valx
声明特征a
,并覆盖x
,则可以将其覆盖为var
(参见下面的代码)。令人惊讶的是,A
中的print()
方法受x
重新分配的影响,即使x
是A
中的值。这是一个bug还是一个特性
代码:
但正如第一个案例所显示的,继承可能会导致副作用,而这显然不是
A
中的意图。如何保护值不被继承更改?您可以将val
设置为final,即完全禁止覆盖它。
如果在类中定义val
,默认情况下它是final
此外,如果需要使用var
覆盖val
,但不希望setter是公共的,可以这样说:
override var x = 1
private set
用var
覆盖val
是一项功能。这相当于添加一个set方法,而在超类中只有一个get方法。这在实现一些模式时非常重要,比如只读接口
没有办法“保护”您的val
不被重写,因为val
并不意味着“不可变引用”,而只是“只读属性”。换句话说,当您的traitA
声明了一个val
,这意味着通过A
类型的引用,客户无法编写此val
,没有其他预期的或确实可能的保证
s s分号在Kotlin是可选的,可以随意省略它们,
我会认为这是一个特性,因为VALL变为var,使用较弱的使用限制,<强>不能中断任何超类代码< /强>。使用可见性修改器可以观察到类似情况:
trait A {
protected fun print() {
...
}
}
class AImpl: A {
public override fun print() {
...
}
}
在本例中,子类也放宽了可见性限制,尽管有些人将此技术视为反模式
如何保护值不被继承更改
在kotlin中,您可以使用open
修饰符显式定义子类是否可以覆盖任何特定的类成员。但是,在traits中,默认情况下所有成员都是打开的。解决方案是用类替换trait,这样您就可以控制继承:
abstract class A {
fun print() {
...
}
val x : Int = 2;
}
class AImpl(x : Int) : A() {
override var x = x // compilation error
}
trait A {
protected fun print() {
...
}
}
class AImpl: A {
public override fun print() {
...
}
}
abstract class A {
fun print() {
...
}
val x : Int = 2;
}
class AImpl(x : Int) : A() {
override var x = x // compilation error
}