1

特质Trait

在scala中,有一个既类似java接口的又类似java抽象类的概念,叫做特质Trait。
我们可以把他当作接口来用,使用方式和java的接口类似,也可以把他当作抽象类使用,使用方式就和java的抽象类类似。但是不管用接口还是抽象的方式,都是使用关键字extends
接口的方式:

trait ScalaTrait {
  def printInfo(): Unit
}

class ScalaClass extends ScalaTrait {
  override def printInfo(): Unit = {
    println("ScalaClass")
  }
}

object ScalaClass {
  def main(args: Array[String]): Unit = {
    val scalaClass = new ScalaClass
    scalaClass.printInfo()
  }
}

抽象类的方式:

trait ScalaTrait2 {
  def printInfo(): Unit

  def printInfo2(): Unit = println("printInfo2")
}

class ScalaClass2 extends ScalaTrait2 {
  override def printInfo(): Unit = {
    println("ScalaClass2")
  }
}

object ScalaClass2 {
  def main(args: Array[String]): Unit = {
    val scalaClass = new ScalaClass2
    scalaClass.printInfo()
    scalaClass.printInfo2()
  }
}

多个Trait继承

抽象类是不能多继承的,但是Trait是可以多继承的,多个Trait直接用with关键字。
下面例子中,ScalaClass3 既有ScalaTraitA01的方法实现,也有ScalaTraitA02的方法实现。

trait ScalaTraitA01 {
  def printInfo01(): Unit
}

trait ScalaTraitA02 {
  def printInfo02(): Unit
}

class ScalaClass3 extends ScalaTraitA01 with ScalaTraitA02 {
  def printInfo01(): Unit = {
    println(s"printInfo01")
  }

  def printInfo02(): Unit = {
    println(s"printInfo02")
  }
}

object ScalaClass3 {
  def main(args: Array[String]): Unit = {
    val scalaClass = new ScalaClass3
    scalaClass.printInfo01()
    scalaClass.printInfo02()
  }
}

重复属性

比如继承的多个Trait都有某个属性,那调用的时候,就不知道是调用哪个属性,此时就需要子类去重写这个值,比如str通过override重写定义为ScalaClass4。

trait ScalaTraitB01 {
  val str: String = "strB01"

  def printInfo01(): Unit
}

trait ScalaTraitB02 {
  val str: String = "strB02"

  def printInfo02(): Unit = println("printInfo02 " + str)
}

class ScalaClass4 extends ScalaTraitB01 with ScalaTraitB02 {
  override val str: String = "ScalaClass4"

  override def printInfo01(): Unit = {
    println(str)
  }
}

object ScalaClass4 {
  def main(args: Array[String]): Unit = {
    val scalaClass = new ScalaClass4
    scalaClass.printInfo01()
    scalaClass.printInfo02()
  }
}

重复方法

ScalaTraitC01和ScalaTraitC02都有printInfo01方法,子类调用super.printInfo01(),结果显示调用的是ScalaTraitC02里的方法。
在Trait调用链中,是从with的最右边往左边调用。

trait ScalaTraitC01 {
  val str: String = "strC01"

  def printInfo01(): Unit = println("printInfoC01 " + str)
}

trait ScalaTraitC02 {
  val str: String = "strC02"

  def printInfo01(): Unit = println("printInfoC02 " + str)
}

class ScalaClass5 extends ScalaTraitC01 with ScalaTraitC02 {
  override val str: String = "ScalaClass5"

  override def printInfo01(): Unit = {
    super.printInfo01()
  }
}

object ScalaClass5 {
  def main(args: Array[String]): Unit = {
    val scalaClass = new ScalaClass5
    scalaClass.printInfo01()
  }
}

我们可以通过这个特性实现责任链模式:

trait ScalaTraitD00 {
  def printInfo01(): Unit = {}
}

trait ScalaTraitD01 extends ScalaTraitD00 {
  override def printInfo01(): Unit = {
    println("ScalaTraitD01")
    super.printInfo01()
  }
}

trait ScalaTraitD02 extends ScalaTraitD00 {
  override def printInfo01(): Unit = {
    println("ScalaTraitD02")
    super.printInfo01()
  }
}

trait ScalaTraitD03 extends ScalaTraitD00 {
  override def printInfo01(): Unit = {
    println("ScalaTraitD03")
    super.printInfo01()
  }
}

class ScalaClass6 extends ScalaTraitD01 with ScalaTraitD02 with ScalaTraitD03 {

  override def printInfo01(): Unit = {
    super.printInfo01()
  }
}

object ScalaClass6 {
  def main(args: Array[String]): Unit = {
    val scalaClass = new ScalaClass6
    scalaClass.printInfo01()
  }
}

打印结果如下:

ScalaTraitD03
ScalaTraitD02
ScalaTraitD01

大军
847 声望183 粉丝

学而不思则罔,思而不学则殆


引用和评论

1 篇内容引用
0 条评论