Step into Scala - 15 - 特质

来源:互联网 发布:sql select 两个字段 编辑:程序博客网 时间:2024/06/05 16:10

目录

    • 特质
      • 概念
      • 定义一个特质
      • 实现特质
      • 继承特质
      • 带有特质的对象
      • 特质的构造顺序
      • 叠加在一起的特质
      • 什么时候应该使用特质而不是抽象类

摘要

特质概念,定义特质,抽象方法,抽象属性,实现多个特质,继承特质,带有特质的对象,特质构造顺序,特质与抽象类

特质

概念

  • 特质是一些字段和行为的集合
  • 特质可以同时拥有抽象方法和具体方法
  • 一个类可以实现多个特质
  • 特质不能有带参数的构造函数。

定义一个特质

trait Logger {  //字段  val brand: String  val minLength: Int  //行为  //抽象方法  def log(msg: String)  //带有具体实现  def echo(msg: String) {    println(msg)  }  //依赖抽象方法  def info(msg: String) = log("INFO" + msg)}
  • 特质使用关键字 trait 声明
  • 特质中可以有抽象方法和抽象属性,且复写时无需使用关键字 override
  • 特质中的方法可以互相依赖,即使是依赖抽象方法

实现特质

实现特质使用关键字 extends,之后如果需要实现多个特质时,则使用关键字 with

class ConsoleLogger extends Logger with Cloneable with Serializable {  //实现抽象方法  def log(msg: String): Unit = println(msg)  //实现抽象属性  val minLength: Int = 1}

以上代码实际内部是将 Logger with Cloneable with Serializable 看作了一个整体类进行了继承。

继承特质

trait Logger {  def show(msg: String) {}  def log(msg: String)}trait OutputLogger extends Logger{  override def show(msg: String): Unit = println(msg)  //重写抽象方法  abstract override def log(msg: String): Unit = {    super.log(msg)  }}
  • 特质也可以继承特质
  • 如果需要在重写的抽象方法中调用父类特质的抽象方法,必须将方法本身声明为抽象的,即 abstract

带有特质的对象

可以为单个对象添加特质

trait Logger {  def show(msg: String) {}}trait OutputLogger extends Logger{  override def show(msg: String): Unit = println(msg)}class LoggerExample extends Logger {}val logger1 = new LoggerExamplelogger1.say("hello")//为单个对象添加特质val logger2 = new LoggerExample with OutputLoggerlogger2.say("hello world") //hello world

特质的构造顺序

特质构造顺序遵循以下原则

  • 首先调用超类的构造器
  • 特质构造器在超类构造器之后,类构造器之前执行
  • 特质由左至右被构造
  • 每个特质中,父特质先被构造
  • 如果多个特质有同一个父特质,且父特质已被构造了,则不会被再次构造
  • 所有特质构造完毕,子类才被构造

有如下类

class SavingAccount extends Account with FileLogger with ShortLogger

则构造顺序为

  1. Account
  2. Logger
  3. FileLogger
  4. ShortLogger
  5. SavingAccount

在 ShortLogger 中调用 super 会执行 FileLogger 的方法

叠加在一起的特质

一般情况下,特质总是从最后一个开始向前执行

trait Logger {  def show(msg: String) {}}trait TimeStampLogger extends Logger {  override def show(msg: String): Unit = {    super.show(new Date() + " " + msg)  }}trait ShortLogger extends Logger {  val maxLength = 15  override def show(msg: String): Unit = {    super.show(      if (msg.length <= maxLength) msg else msg.substring(0, maxLength - 3) + "..."    )  }}class LoggerExample extends Logger {}val logger3 = new LoggerExample with OutputLogger with TimeStampLogger with ShortLoggerlogger3.show("hello world logger3") //Mon Feb 16 11:46:06 CST 2015 hello world ...val logger4 = new LoggerExample with OutputLogger with ShortLogger with TimeStampLoggerlogger4.show("hello world logger4") //Mon Feb 16 1...

什么时候应该使用特质而不是抽象类?

如果你想定义一个类似接口的类型,你可能会在特质和抽象类之间难以取舍。这两种形式都可以让你定义一个类型的一些行为,并要求继承者定义一些其他行为。一些经验法则:

  • 优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。
  • 如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行。
  • 如果需要类从 Java类继承,使用抽象类。
  • 如果需要考虑效率问题,使用抽象类。Java的动态绑定机制决定了直接方法要快于接口方法。而特质最终是被编译成接口。
0 0
原创粉丝点击