2016-03-02 33 views
4

一個奇怪的NullPointerException異常的代碼放在這裏:在斯卡拉

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) 
} 

這三個子類都OK,除了LineElementF,與val lef = new LineElementF("Wrong")

回答

4

這NPE創建實例時拋出NullPointerException發生在高度初始化。在高度初始化時,LineElementF的val內容未被初始化。

可以通過聲明都高度避免這種NPE和寬度懶:

lazy val height = contents.length 
lazy val width = if(height ==0) 0 else contents(0).length 
+0

謝謝,但你能告訴我爲什麼其他兩個子類運作良好嗎? – monk

+0

區別在於,你將'contents'一次定義爲'val',一次定義爲'def。 'val'的右邊部分在施工時進行評估,這是'def'at通話時間之一。您可以將內容聲明爲「lazy val contents」,以便在第一次調用它時僅對它進行一次評估。 –

+0

仍然困惑,但非常感謝 – monk

1

Scala語言也有一個特殊的語法(有時稱爲early definitions or early initilizer),它允許前執行子類的構造函數其超類的構造函數:

class LineElementEI(s: String) extends { 
    override val contents = Array(s) 
} with Element 

澄清爲何經常「遲到初始化」不與你的工作LineElementF:在超的身體,你正試圖評估contents.length,但子類的正文僅在超類後評估,所以contents仍然是null。您可以解決這個問題,可以在依賴於子類初始化的所有字段上使用惰性評估,或者如上所示更改初始化順序。