scala中一个奇怪的NullPointerException
代码如下:scala中一个奇怪的NullPointerException,scala,Scala,代码如下: abstract class Element { def contents: Array[String] val height = contents.length val width = if(height ==0 ) 0 else contents(0).length override def toString = contents(0) } class ArrayElement(override val contents: Array[String]) exte
abstract class Element {
def contents: Array[String]
val height = contents.length
val width = if(height ==0 ) 0 else contents(0).length
override def toString = contents(0)
}
class ArrayElement(override val contents: Array[String]) extends Element
class LineElementT(s: String) extends Element {
override def contents = Array(s)
}
class LineElementF(s: String) extends Element {
override val contents = Array(s)
}
这三个子类是正常的,除了
LineElementF
,它在使用val lef=newlineelementf(“错误”)
创建实例时抛出一个NullPointerException
,此NPE发生在高度初始化时。高度初始化时,LineElementF的val内容未初始化
通过将高度和宽度都声明为惰性,可以避免此NPE:
lazy val height = contents.length
lazy val width = if(height ==0 ) 0 else contents(0).length
Scala语言还有一种特殊的语法(有时称为),它允许在其超类的构造函数之前执行子类的构造函数:
class LineElementEI(s: String) extends {
override val contents = Array(s)
} with Element
要澄清为什么常规的“延迟初始化”不适用于您的
LineElementF
:在超类的主体中,您试图计算内容。length
,但子类的主体仅在超类之后计算,因此内容
仍然是null
。您可以通过对依赖于子类初始化的所有字段使用惰性求值来解决此问题,也可以如上所示更改初始化顺序。谢谢,但您能否告诉我为什么其他两个子类工作得很好?区别在于,您将内容定义为val
和def。val`的右侧部分在构造时进行评估,而def
的右侧部分在调用时进行评估。您可以将内容声明为lazy val contents
,以便在第一次调用时仅对其求值一次。