转载:https://www.cnblogs.com/HeQiangJava/p/6711527.html


  • 我们可以将 trait 作为接口来使用,此时的 trait 就与 Java 中的接口非常类似
  • trait 中可以定义具体方法,也可以定义抽象方法,就与抽象类中的抽象方法一样,只要不给出方法的具体实现即可
  • 类可以使用 extends 关键字继承 trait,注意,这里不是 implement,而是 extends,在 scala 中没有 implement 的概念,
    无论继承类还是 trait,统一都是 extends
  • 类继承 trait 后,必须实现其中的抽象方法,实现时不需要使用 override 关键字
  • scala 不支持对类进行多继承,但是支持多重继承 trait,使用 with 关键字即可
object TraitApp {
  def main(args: Array[String]): Unit = {
    val p = new Person3("赵敏")
    p.sayHello("How are you")

    val p2 = new Person3("张无忌")
    p.makeFriends(p2)
  }
}


trait HelloTrait {
  val eyeNum: Int = 2 // 定义具体字段
  def sayHello(name: String)
}

trait MakeFriendsTrait {
  val msg: String // 定义抽象字段
  def makeFriends(p: Person3)
}

class Person3(val name: String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable {
  val msg: String = "实现具体字段,不需要使用override关键字"

  // 类继承trait后,必须实现其中的抽象方法,实现时不需要使用override关键字
  def sayHello(name: String) = println("Hello, " + name)

  def makeFriends(p: Person3) = println("Hello, my name is " + name + ", your name is " + p.name)
}

一、在创建类的对象时,指定该对象混入某个trait

这样,就只有这个对象混入该 trait 的方法,而类的其他对象则没有

object TraitApp {
  def main(args: Array[String]): Unit = {
    val p1 = new Person("leo")
    p1.sayHello
    val p2 = new Person("jack") with MyLogger // new Person 的时候混入 MyLogger
    p2.sayHello
  }
}


trait Logged {
  def log(msg: String) {}
}
trait MyLogger extends Logged {
  override def log(msg: String) { println("log: " + msg) }
}
class Person(val name: String) extends Logged {
  def sayHello { println("Hi, I'm " + name); log("sayHello is invoked!") }
}

二、trait 责任链模式

  • Scala中支持让类继承多个 trait 后,依次调用多个 trait 中的同一个方法,只要让多个 trait 的同一个方法中,在最后都执行super.方法即可
  • 类中调用多个 trait 中都有的这个方法时,首先会从最右边的 trait 的方法开始执行,然后依次往左执行,形成一个“调用链条
  • 这种特性非常强大,其实就相当于设计模式中的责任链模式的一种具体实现依赖
object TraitApp {
  def main(args: Array[String]): Unit = {
    val p = new Person4("world")
    p.sayHello
  }
}


trait Handler {
  def handle(data: String) {}
}

trait DataValidHandler extends Handler {
  override def handle(data: String) {
    println("check data: " + data)
    super.handle(data)
  }
}

trait SignatureValidHandler extends Handler {
  override def handle(data: String) {
    println("check signature: " + data)
    super.handle(data)
  }
}

class Person4(val name: String) extends SignatureValidHandler with DataValidHandler {
  def sayHello = {
    println("Hello, " + name); handle(name)
  }
}

运行输出

Hello, world
check data: world
check signature: world

三、覆盖父trait的抽象方法

  • trait 中,是可以覆盖父 trait 的抽象方法的
  • 但是覆盖时,如果使用了 super.方法 的代码,则无法通过编译。
    因为super.方法 就会去掉用父 trait 的抽象方法,此时子 trait 的该方法还是会被认为是抽象的
  • 此时如果要通过编译,就得给子 trait 的方法加上 abstract override 修饰
trait Logger {
  def log(msg: String)
}

trait MyLogger extends Logger {
  // 方法体中调用父级super.log(msg),还是抽象方法,所以编译会报错
  abstract override def log(msg: String) { super.log(msg) }
}

四、trait的构造机制

Scala 中,trait 也是有构造代码的,也就是 trait 中的,不包含在任何方法中的代码

而继承了 trait 的类的构造机制如下:

  1. 父类的构造函数执行;
  2. trait 的构造代码执行,多个 trait 从左到右依次执行;
  3. 构造 trait 时会先构造父 trait,如果多个 trait 继承同一个父 trait,则父 trait 只会构造一次;
  4. 所有 trait 构造完毕之后,子类的构造函数执行
object TraitApp {
  def main(args: Array[String]): Unit = {
    new Student
  }
}


class Person {
  println("0.Person's constructor!")
}

trait Logger {
  println("1.Logger's constructor!")
}

trait MyLogger extends Logger {
  println("2.MyLogger's constructor!")
}

trait TimeLogger extends Logger {
  println("3.TimeLogger's constructor!")
}

class Student extends Person with MyLogger with TimeLogger {
  println("4.Student's constructor!")
}

运行输出

0.Person's constructor!
1.Logger's constructor!
2.MyLogger's constructor!
3.TimeLogger's constructor!
4.Student's constructor!

五、trait field的初始化

object TraitApp {
  def main(args: Array[String]): Unit = {
    val p = new{ val name="dog" } with Person4 with Hello
  }
}

trait Hello {
  val name: String;
  println(name.toUpperCase)
}

class Person4{

}

另一种提前定义

object TraitApp {
  def main(args: Array[String]): Unit = {
    val p = new Person
  }
}

trait Hello {
  val name: String; println(name.toString)
}

class Person extends {
  val name: String = "hello"
} with Hello

定义为 lazy 的方式

object TraitApp {
  def main(args: Array[String]): Unit = {
    var p =  new Person4
  }
}

trait Hello {
  lazy val name: String = null;
  println(name.toString)
}

class Person4 extends Hello {
  override lazy val name = "hello"
}

六、trait继承class

Scala 中,trait 也可以继承自 class,此时这个 class 就会成为所有继承该 trait 的类的父类

class MyUtil {
  def printMessage(msg: String) = println(msg)
}

trait Logger extends MyUtil {
  def log(msg: String) = printMessage("log: " + msg)
}

class Person(val name: String) extends Logger {
  def sayHello {
    log("Hi, I'm " + name)
    printMessage("Hi, I'm " + name)
  }
}