为什么重写的变量在Scala中得到错误的值?

him*_*ian 10 scala

我在Scala中有一个A类,就像这个:

class A {
  val a = 3
  lazy val b = 2
  println("a = " + a)
  println("b = " + b)
}
Run Code Online (Sandbox Code Playgroud)

接下来,我将这个类扩展到另一个B类:

class B extends A {
  override val a = 4
  override lazy val b = 3
}
Run Code Online (Sandbox Code Playgroud)

现在,当我创建一个对象时class B,我得到以下输出:

a = 0  //the default value of int is zero `0` in Scala
b = 3
Run Code Online (Sandbox Code Playgroud)

而我期望输出为:

a = 3
b = 2
Run Code Online (Sandbox Code Playgroud)

我的问题是如何知道println()函数中class A定义的值class B,但仅限于b和不是a

Xav*_*hot 7

docs.scala-lang.org - tutorials - initialization-order提供了完整的解释.


为了看清楚,让我们在课堂上B和课堂上打印相同的东西A:

class A {
  val a = 3
  lazy val b = 2
  println("A: a = " + a)
  println("A: b = " + b)
}

class B extends A {
  override val a = 4
  override lazy val b = 3
  println("B: a = " + a)
  println("B: b = " + b)
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,new B()产生:

A: a = 0
A: b = 3
B: a = 4
B: b = 3
Run Code Online (Sandbox Code Playgroud)

非延迟val变量的初始化顺序由下式给出:

在没有"早期定义"(见下文)的情况下,严格的val的初始化按以下顺序进行.

  1. 超类在子类之前完全初始化.
  2. 否则,按声明顺序.

因此A在之前完全初始化B.

val不能多次初始化.因此,当首先处理超类时,Scala内部为它提供了一个默认值(0对于a Int,nullfor String,...)A.

因此,它0首先打印(初始化时A)然后4(初始化时B).


使用lazy vals是scaladoc提出的绕过此限制的解决方案.