我正在阅读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)
}
答案 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"
}]
}
之间有一种“循环依赖”。