Scala中的override


Scala中的override

override是覆蓋的意思,在很多語言中都有,在scala中,override是非常常見的,在類繼承方面,它和java不一樣,不是可寫可不寫的了,而是必須寫的。如果不寫而覆蓋了對應的屬性或者方法的話,編譯器就會報錯了。今天把scala中的override的各種地方都整理了一遍,以方便以后翻閱。

基礎用法

/*
基本的override特性
*/
class A {
  val nameVal = "A"
  var nameVar = "A"

  def foo: String = {
    "A.foo"
  }
}

class B extends A {
  override val nameVal = "B"
  //override var nameVar = "B"  "variable nameVar cannot override a mutable variable"
  override def foo: String = {
    "B.foo"
  }
}

val b1 = new B
b1.foo
b1.nameVal
b1.nameVar

val b2 : A = new B
b2.foo
b2.nameVal
b2.nameVar = "B"
b2.nameVar


輸出:


defined class A


defined class B


b1: B = B@9825fab
res0: String = B.foo
res1: String = B
res2: String = A

b2: A = B@c46c4a1
res3: String = B.foo
res4: String = B
b2.nameVar: String = B
res5: String = B

當一個類extends另外一個類的時候,override的規則基本如下:

  • 子類中的方法要覆蓋父類中的方法,必須寫override(參見foo)
  • 子類中的屬性val要覆蓋父類中的屬性,必須寫override(參見nameVal)
  • 父類中的變量不可以覆蓋(參見nameVar)

在抽象類中可以不用寫override

/*
trait的extent不需要override
*/
trait T {
  def foo : String
  def bar : String
}

class TB extends T {
  def foo: String = {
    "TB.foo"
  }

  def bar: String = "TB.bar"
}

val tb = new TB
tb.foo
tb.bar


trait TT  extends T {
  def bar :String = "TT.bar"
}

class TTB extends TT {
  def foo: String = "TTB.foo"
}
val ttb = new TTB
ttb.foo
ttb.bar

輸出:

defined trait T


defined class TB


tb: TB = TB@2fb497ea
res6: String = TB.foo
res7: String = TB.bar


defined trait TT



defined class TTB



ttb: TTB = TTB@346c06af
res8: String = TTB.foo
res9: String = TT.bar

T是特性類,它定義了兩個抽象方法,foo和bar。TB的類繼承和實現了T特性類,這個時候,TB類中的foo和bar前面的override是可寫可不寫的。這里初步看下TB類中的foo和bar前面的override寫和不寫感覺都一樣,但是一旦有鑽石結構的類繼承,這個override的作用就體現出來了。這個我們后續說。

TT和TTB的例子也是說明了下trait繼承trait是不需要使用override的。

abstrct class 也不需要使用override

/*
abstrct class 不需要override
*/
abstract class PA(name: String) {
  def hello: String
}

class PB(name: String) extends PA(name) {
  def hello : String = s"hello ${name}"
}

val pb = new PB("yejianfeng")
pb.hello

輸出:

defined class PA

defined class PB

pb: PB = PB@62840167
res10: String = hello yejianfeng

abstract class和trait的特性主要是在是否有構造參數,在override方面都是一樣的。

鑽石結構

所謂的鑽石結構就是一個菱形的結構,一個基類,兩個子類,最后一個類又繼承這兩個子類。那么如果這兩個子類都包含一個基類的方法,那么最后的這個類也有這個方法,選擇繼承那個子類呢?

/*
鑽石結構
*/
trait Animal {
  def talk: String
}

trait Cat extends Animal {
  def talk: String = "I am Cat"
}

trait Monkey extends Animal {
  def talk: String = "I am monkey"
}

trait Dog extends Animal {
  override def talk: String = "I am Dog"
}

val kittyDog = new Cat with Dog
kittyDog.talk

class MonkeyCat extends Monkey with Cat {
  override def talk: String = "I am monkeyCat"
}

val monkeyCat = new MonkeyCat
monkeyCat.talk


輸出:

defined trait Animal



defined trait Cat



defined trait Monkey



defined trait Dog



kittyDog: Cat with Dog = $anon$1@5378ef6d
res11: String = I am Dog

defined class MonkeyCat



monkeyCat: MonkeyCat = MonkeyCat@1e444ce6
res12: String = I am monkeyCat

在這個例子中,Animal是基類,Cat和Dog是子類,kittyDog是繼承了Cat和Dog,那么kittyDog里面的talk使用的是Cat和Dog中有標示override的那個方法。這個時候override的作用就體現出來了。

參數復寫使用override

我們可以直接在構造函數里面使用override重寫父類中的一個屬性。我理解這個更多是語法糖的一個功能。

/*
參數復寫
*/
class Person(val age : Int){
  val name = "no name"
}

class XiaoMing(age: Int, override val name: String) extends Person(age){

}
val xiaoming = new XiaoMing(12, "xiaoming")
xiaoming.name


輸出:
defined class Person



defined class XiaoMing


xiaoming: XiaoMing = XiaoMing@2eef0f3c
res13: String = xiaoming

總結

scala中的override基本是強制性的。這個我比較贊同,這樣就減少了思維邏輯的負擔,看到一個類中的一個方法的時候,就明白了這個方法是否是覆寫父類的方法。但是感覺由於scala類的繼承的靈活性,比如鑽石結構里面,要知道最終的類使用的方法是什么,就需要了解每個父類的情況,這個還是有點糾結的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM