1. 程式人生 > 其它 >Scala中特質的使用以及特質衝突

Scala中特質的使用以及特質衝突

說明

  • Scala語言中,採用特質trait來代替介面的概念。也就是說,多個類中,具有相同的特徵時,可以將此特徵獨立出來,採用trait關鍵字宣告。
  • Scala特質中,既可以有抽象屬性和抽象方法,也可以有非抽象屬性和非抽象方法。
  • 一個類可以混入多個特質。

混入單特質

object Scala03_Trait {
  def main(args: Array[String]): Unit = {
    val stu:PersonTrait03 = new Student03
    stu.sleep()
    stu.eat()
    println(stu.name)
  }
}


trait
PersonTrait03 { // 特質中既可以有抽象屬性和抽象方法 var name: String def sleep(): Unit // 也可以有非抽象屬性和非抽象方法 var age: Int = 18 def eat(): Unit = { println("Person eat") } } // 混入特質 class Student03 extends PersonTrait03 { // 重寫特質中的抽象方法和屬性 override var name: String = "Li Ming" override
def sleep(): Unit = { println("Student sleep") } }

混入多個特質

  • 沒有類繼承的混入多個特質:extends trait1 with trait2 with …
  • 有類繼承的混入多個特質,先繼承類,再混入特質:extends ClassName with trait1 with trait2 …
  • 建立物件時,動態混入特質:new ClassName with trait1 {重寫抽象方法}。
object Scala04_Trait {
  def main(args: Array[String]): Unit = {
/*val clzz = new MyClass04 clzz.mA() val clazz1 = new MyClass004 clazz1.mB()*/ // 動態的混入特質 val clzz004 = new MyClass004 with TraitC { override def mC(): Unit = { println("mC") } } clzz004.mC() } } trait TraitA { def mA(): Unit } trait TraitB { def mB(): Unit } trait TraitC { def mC(): Unit } class Super { } // 沒有類繼承的混入多個特質 class MyClass04 extends TraitA with TraitB with TraitC { override def mA(): Unit = { println("mA") } override def mB(): Unit = { println("mB") } override def mC(): Unit = { println("mC") } } // 有繼承,混入多個特質。繼承的類放在第一個位置 class MyClass004 extends Super with TraitA with TraitB{ override def mA(): Unit = { println("mA") } override def mB(): Unit = { println("mB") } }

特質衝突(普通衝突)

  • 當一個類混入多個特質時,如果兩個特質之間沒有關係,但是有同名的抽象方法,需要重寫抽象方法。
  • 當一個類混入多個特質時,如果兩個特質之間沒有關係,但是有同名的非抽象方法,需要重寫非抽象方法。
object Scala05_Trait {
  def main(args: Array[String]): Unit = {
    val p = new Person05
    p.m1()

    val p2 = new Person005
    p2.m1()
  }
}

trait Person05TraitA {
  def m1(): Unit
}

trait Person05TraitB {
  def m1(): Unit
}

class Person05 extends Person05TraitA with Person05TraitB {
  override def m1(): Unit = {
    println("Person05中重寫的m1方法")
  }
}

trait Person005TraitA {
  def m1(): Unit = {
    println("Person005TraitA m1")
  }
}

trait Person005TraitB {
  def m1(): Unit = {
    println("Person005TraitA m1")
  }
}

class Person005 extends Person005TraitA with Person005TraitB {
  override def m1(): Unit = {
    println("Person005中重寫的m1方法")
  }
}

特質疊加(鑽石問題)

在這裡插入圖片描述

說明

特質A和特質B分別混入了特質C,特質A和特質B都重寫了特質C中的m1方法。一個類同時混入特徵A和特徵B,那麼這個類中的m1方法執行時是哪個方法呢?這就是鑽石問題。

程式碼

object Scala06_Trait {
  def main(args: Array[String]): Unit = {
    val operation = new MyOperation
    println(operation.m1())		// 我的操作是:向HDFS向資料庫插入資料
  }
}

trait Operation {
  def m1(): String = {
    "插入資料"
  }
}

trait DBOperation extends Operation {
  override def m1(): String = {
    "向資料庫" + super.m1()  }
}

trait HDFSOperation extends Operation {
  override def m1(): String = {
    "向HDFS" + super.m1()
  }
}

class MyOperation extends DBOperation with HDFSOperation with Operation {
  override def m1(): String = {
    "我的操作是:" + super.m1()
  }
}

執行結果解析

  • 第一步:列出混入的第一個特質的繼承關係,作為臨時順序。
    DBOperation --> Operation
  • 第二步:列出第二個特質的繼承關係,並將該順序疊加到第一個特質的順序之前。需要注意的是,已經出現的特質不再重複。
    HDFSOperation --> DBOperation --> Operation
  • 第三步:將子類放在臨時疊加順序的第一個,為最終疊加順序。
    MyOperation --> HDFSOperation --> DBOperation --> Operation

注意:案例中的super,不是表示其父特質物件,而是表示上述疊加順序中的下一個特質。