在前面的例子我們看到類型為 Element 的變量可以保存 ArrayElement 類型的對(duì)象,這種現(xiàn)象稱為“多態(tài)”。也就是基類類型的變量可以保存其子類類型的對(duì)象,到目前為止我們定義了兩個(gè) Element 的子類,ArrayElement 和 LineElement。你還可以定義其它子類,比如:
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)
}
結(jié)合前面定義的類定義,我們就有了如下圖所示的類層次關(guān)系:
Scala 將接受所有的下列賦值,因?yàn)橘x值表達(dá)式的類型符合定義的變量類型:
val e1: Element = new ArrayElement(Array("hello", "world"))
val ae: ArrayElement = new LineElement("hello")
val e2: Element = ae val
e3: Element = new UniformElement('x', 2, 3)
若你檢查繼承層次關(guān)系,你會(huì)發(fā)現(xiàn)這四個(gè) val 定義的每一個(gè)表達(dá)式,等號(hào)右側(cè)表達(dá)式的類型都在將被初始化的等號(hào)左側(cè)的 val 類型的層次之下。
另一方面,如果調(diào)用變量(對(duì)象)的方法或成員變量,這個(gè)過(guò)程是一個(gè)動(dòng)態(tài)綁定的過(guò)程,也就是說(shuō)調(diào)用哪個(gè)類型的方法取決于運(yùn)行時(shí)變量當(dāng)前的類型,而不是定義變量的類型。
為了顯示這種行為,我們?cè)?Element 中添加一個(gè) demo 方法,定義如下:
abstract class Element {
def demo() {
println("Element's implementation invoked")
}
}
class ArrayElement extends Element {
override def demo() {
println("ArrayElement's implementation invoked")
}
}
class LineElement extends ArrayElement {
override def demo() {
println("LineElement's implementation invoked")
}
}
// UniformElement inherits Element’s demo
class UniformElement extends Element
如果你使用交互式 Scala 解釋器來(lái)測(cè)試,你可以定義如下的方法:
def invokeDemo(e: Element) {
e.demo()
}
下面我們分別使用 ArrayElement,LineElement 和 UniformElement 來(lái)調(diào)用這個(gè)方法:
scala> invokeDemo(new ArrayElement)
ArrayElement's implementation invoked
scala> invokeDemo(new LineElement)
LineElement's implementation invoked
scala> invokeDemo(new UniformElement)
Element's implementation invoked
可以看到由于 ArrayElement 和 LineElement 重載了 Element 的 demo 方法,因此調(diào)用 invokeDemo 時(shí)由于“動(dòng)態(tài)綁定”因此會(huì)調(diào)用這些子類的 demo 方法,而由于 UniformElement 沒(méi)有重載 Element 的 demo 方法,動(dòng)態(tài)綁定時(shí)也會(huì)調(diào)用 UniformElement 的 demo 方法(但此時(shí)實(shí)際為基類的 demo 方法)。
更多建議: