NPE在使用scala Array.fill

时间:2017-02-18 07:08:35

标签: scala

我正在阅读Lex Spoon的 Scala编程,第三版;比尔维纳斯; Martin Odersky ,并在此过程中尝试了一些例子。

以下示例构成了本书

abstract class Element {
  def contents: Array[String]
  val height = contents.length
  val width = if (height == 0) 0 else contents(0).length
}

class UniformElement(
  ch: Char,
  override val width: Int,
  override val height: Int
) extends Element {
  private val line = ch.toString * width
  def contents = Array.fill(height)(line)
}

val e: Element = new UniformElement('x', 2, 3)

在REPL或Eclipse工作表中尝试时给出 java.lang.NullPointerException

但如果我改变

  private val line = ch.toString * width

  private def line = ch.toString * width

没有观察到任何错误。

我无法理解为什么? 有人可以解释一下吗?

我正在使用scala 2.11.8

修改

@acidghost 回答后,我更改了类UniformElement ,如下所示,并没有获得NPE。 :)

class UniformElement(
  ch: Char,
  val w: Int,
  val h: Int
) extends Element {
  override val width: Int = w
  override val height: Int = h
  private val line = ch.toString * width
  def contents = Array.fill(height)(line)
}

1 个答案:

答案 0 :(得分:5)

这里的问题是,当您定义contents时,构造函数中仍未定义line。如果行是val,则它不会选择被覆盖的width,而是使用抽象的contents,而后者仍使用width,这仍然是未定义的,您将获得NPE。你可以通过查看堆栈跟踪来看到这一点,并注意到抽象类中line的定义引发了NPE。

line被定义为一个方法时,它会在你调用之前执行,到那时内容将被完全定义,因为它可以调用line(另一种方法)定义

结论:contents { "feature": "testFeature", "scenario": [{ "name": "Add numbers", "tag": "@test" }, { "name": "Delete numbers", "tag": "@test123" }] } 之间有一种“循环依赖”。