我正在学习Scala
和Programming in Scala 3rd Ed
,Ch 10, Page 225
,Overriding methods and fields
部分,它说
统一访问原则只是Scala处理的一个方面 字段和方法比Java更统一。另一个区别是 在Scala中,字段和方法属于同一名称空间。这个 使字段可以覆盖无参数方法。对于 例如,您可以更改类中内容的实现 ArrayElement从一个方法到一个字段而不必修改 类Element中内容的抽象方法定义,如图所示 代码清单10.4:
基于该示例的代码是
使用def
abstract class Element {
def contents: Array[String]
val height = contents.length
val width = if (height == 0) 0 else contents(0).length
}
class ArrayElement(contnts: Array[String]) extends Element {
def contents: Array[String] = contnts
}
// --
val ae = new ArrayElement(Array("hello", "world"))
ae.height
ae.width
我得到了
ae: ArrayElement = ArrayElement@7cd3ba8e
res0: Int = 2
res1: Int = 5
将def覆盖为ArrayElement中的val
abstract class Element {
def contents: Array[String]
val height = contents.length
val width = if (height == 0) 0 else contents(0).length
}
class ArrayElement(contnts: Array[String]) extends Element {
val contents: Array[String] = contnts
}
// --
val ae = new ArrayElement(Array("hello", "world"))
ae.height
ae.width
我将NPE
视为
java.lang.NullPointerException
at #worksheet#.Element.<init>(scratch.scala:4)
at #worksheet#.ArrayElement.<init>(scratch.scala:10)
at #worksheet#.ae$lzycompute(scratch.scala:15)
at #worksheet#.ae(scratch.scala:15)
at #worksheet#.#worksheet#(scratch.scala:14)
我错过了什么?
答案 0 :(得分:8)
类级别字段在其他任何内容之前初始化,这意味着已分配null
。您可以将声明设为lazy val
,并且在调用之前不会对其进行初始化。这就是def工作的原因。但是,更好的方法是,不要创建隐藏私有构造函数字段的类公共字段,而是将构造函数字段设置为public,如下所示:
class ArrayElement(val contnts: Array[String]) extends Element {}
由于这里也有一个父类,所以将它标记为重写是好的;
class ArrayElement(override val contnts: Array[String]) extends Element {}
如果这将成为无状态数据容器类,最好的选择是使其成为case class
,其中(在其他几个方面)具有默认的公共字段。
case class ArrayElement(override val contnts: Array[String]) extends Element
这是更惯用的scala,它将为您提供基于值的equals
,hashCode
,模式匹配,更简单的构造(无需new
)