Inheritance 错误或功能:Kotlin允许更改';val';至';var';继承

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覆盖

我刚开始探索科特林的语言。我正在与继承、var&val和副作用作斗争

如果我在
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
并不意味着“不可变引用”,而只是“只读属性”。换句话说,当您的trait
A
声明了一个
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
}