Scala快速入门-8-特质

简介: Scala和Java一样不允许类继承多个超类,特质解决这一局限性类可以实现任意数量的特质当将多个特质叠加在一起时,顺序很重要,其方法先被执行的特质排在更后面Scala特质可以提供方法和字段的实现特质要求实现它们的类具备特定的字段、方法或超类特质可以同时拥有抽象方法和具体方法,而类可以实现多个特质

知识点


  • Scala和Java一样不允许类继承多个超类,特质解决这一局限性
  • 类可以实现任意数量的特质
  • 当将多个特质叠加在一起时,顺序很重要,其方法先被执行的特质排在更后面
  • Scala特质可以提供方法和字段的实现
  • 特质要求实现它们的类具备特定的字段、方法或超类
  • 特质可以同时拥有抽象方法和具体方法,而类可以实现多个特质

当做接口使用的特质


  • Scala特质完全可以像Java的接口一样,使用关键字 trait
  • 不需要将方法声明为abstract,特质中未被实现的方法默认就是抽象的
  • 在子类中重写特质的抽象方法不需要用 override 关键字
package com.gemantic.base
/**
  * @author Yezhiwei
  * @date 18/1/6
  */
object TraitLearn {
  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger
    logger.log("console log message...")
  }
}
trait Logger {
  def log(msg: String)
}
class ConsoleLogger extends Logger {
  override def log(msg: String): Unit = println(msg)
}

说明:

子类实现特质,用 extends 而不是 implements

不需要写 override

如果需要多个特质,可以用with关键字来添加额外的特质,如下代码

class ConsoleLogger extends Logger with Serializable {
  override def log(msg: String): Unit = println(msg)
}

带有具体实现的特质


  • 在Scala的特质中的方法并不需要一定是抽象的
  • 子类从特质得到了一个具体的log方法实现
trait ConsoleLoggerImp {
  def log(msg: String) {println(msg)}
}
class AccountAction extends Account with ConsoleLoggerImp {
  def withdraw(amount: Double): Unit = {
    if (amount > nowBalance) {
      log("insufficient funds")
    } else {
      log("enough funds")
    }
  }
}
object TraitLearn {
  def main(args: Array[String]): Unit = {
    // 当做接口使用的特质
    val logger = new ConsoleLogger
    logger.log("console log message...")
    // 带有具体实现的特质
    val accountAction = new AccountAction
    accountAction.withdraw(1000)
  }
}

带有特质的对象


  • 在构造单个对象时,可以为它添加特质
  • 在定义子类时可以使用不做任何实现的特质,在构造具体对象的时候混入一个更合适的实现
  • 特质中重写抽象方法,必须在方法上使用 abstract 及 override
// 有默认实现,但是什么也没有做
trait Logged {
  def log(msg: String) {}
}
trait FileLogged extends Logged {
  override def log(msg: String): Unit = println("saving file : " + msg)
}
class AccountAction extends Account with Logged {
  def withdraw(amount: Double): Unit = {
    if (amount > nowBalance) {
      log("insufficient funds")
    } else {
      log("enough funds")
    }
  }
}
object TraitLearn {
  def main(args: Array[String]): Unit = {
    // 带有特质的对象,可以混入不同的日志
    val accountActionLogger = new AccountAction with FileLogged
    accountActionLogger.withdraw(1000)
  }
}
// 运行输出结果
saving file : insufficient funds

叠加在一起的特质


  • 可以为类或对象添加多个互相调用的特质,从最后一个开始被处理
// 为日志增加时间戳
trait TimestampLogged extends Logged {
  override def log(msg: String): Unit = super.log(new java.util.Date() + " " +  msg)
}
// 如果日志内容长度超过10,截断
trait ShortLogged extends Logged {
  override def log(msg: String): Unit = super.log(if (msg.length <= 10) msg else msg.substring(0, 10) + "...")
}
object TraitLearn {
  def main(args: Array[String]): Unit = {
    // 带有特质的对象
    val accountActionLogger = new AccountAction with FileLogged with TimestampLogged with ShortLogged
    accountActionLogger.withdraw(1000)
    val accountActionLogger1 = new AccountAction with FileLogged with ShortLogged with TimestampLogged
    accountActionLogger1.withdraw(1000)
  }
}
// 输出结果为
saving file : Sat Jan 06 12:38:07 CST 2018 insufficie...
saving file : Sat Jan 06...
  • 注意上面的特质调用顺序及log方法每一个都将修改过的消息传递给supper.log

特质构造顺序


  • 和类一样,特质也可以有构造器,由字段的初始化和其他特质体中的语句构成
  • 构造器执行顺序

首先调用超类的构造器

特质构造器在超类构造器之后、类构造器之前执行

特质由左到右被构造

每个物质当中,父特质先被构造

如果多个特质共有一个父特质,而那个父特质已经被构造,则不会再次构造

所有的特质构造完毕,子类被构造

  • 示例
class AccountAction extends Account with FileLogged with ShortLogged {
    ...
}

构造器执行顺序如下

超类 Account

Logged ,第一个特质的父特质

FileLogged 第一个特质

ShortLogged 第二个特质,它的父特质Logged已被构造

AccountAction 子类

相关文章
|
5月前
|
Java 大数据 Scala
Scala快速入门--Scala环境搭建【Windows10】图解
Scala快速入门--Scala环境搭建【Windows10】图解
66 0
|
6月前
|
分布式计算 Java Scala
Scala:面向对象、Object、抽象类、内部类、特质Trait(二)
Scala:面向对象、Object、抽象类、内部类、特质Trait(二)
92 0
|
消息中间件 Java 大数据
Scala快速入门
Scala快速入门
104 0
|
Java Scala
scala面向对象编程之trait特质
特质就像是java的implement,是scala中代码复用的基础单元,它可以将方法和字段定义封装起来,然后添加到类中与类继承不一样的是,类继承要求每个类都只能继承一个超类,而一个类可以添加任意数量的特质。特质的定义和抽象类的定义很像,但它是使用trait关键字
117 0
scala面向对象编程之trait特质
Scala快速入门-11-常用集合操作
所有的集合都扩展自Iterable特质 集合有三大类,分别为序列、集和映射 几乎所有集合类,Scala都同时提供了可变和不可变的版本 Scala列表要么是空的,要么拥有一头一尾,其中尾部本身又是一个表列 集是无先后次序的集合 用LinkedHashSet来保留插入顺序,或用SortedSet来按顺序进行迭代 +将元素添加到无先后次序的集合中;+:和:+向前或向后追加到序列;++将两个集合串接在一起;-和--移除元素 映射、折叠和拉链操作是很有用的技巧,用来将函数和操作应用到集合中的元素
|
安全 Java 编译器
Scala快速入门-10-模式匹配与样例类
mathch表达式是一个更好的switch,不会有穿透到下一个分支的问题 如果没有模式能够匹配,会抛出MatchError,可以用case _ 模式来避免,相当于Java中的default 模式可以包含一个随意定义的条件,称做守卫 可以匹配数组、列表、元组等模式,然后将匹配到不同部分绑定到变量 样例类及密封类的模式匹配 用Option来存放可能存在也可能不存在的值,比null更安全
Scala快速入门-9-高阶函数
作为值的函数 创建匿名函数 带函数参数的函数 闭包 柯里化
|
Java Scala
Scala快速入门-7-继承
继承类 extends 重写方法时必须用override 只有主构造器可以调用超类的主构造器 重写字段 抽象类、字段
Scala快速入门-6-单例对象及伴生对象
• 用对象作为单例或存放工具方法,Scala没有静态方法或字段 • 类可以有一个同名的伴生对象 • 对象的apply方法通常用来构造伴生类的新实例 • Scala的main函数定义 单例对象
|
Java Scala
Scala快速入门-5-类定义
每个类都有一个主构造器,这个构造器和类的定义“交织”在一起,它的参数直接成为类的字段,主构造器执行类体中所有的语句 类中的字段自动带getter和setter方法 用@BeanProperty注解生成JavaBean的getXxx/setXxx方法 辅助构造器是可选的,它们都叫做this