文章目录
特质(trait)
scala中没有Java中的接口(interface),替代的概念是——特质
概念
- 特质是scala中代码复用的基础单元
- 它可以将方法和字段定义封装起来,然后添加到类中
- 与类继承不一样的是,类继承要求每个类都只能继承
一个
超类,而一个类可以添加任意数量
的特质。- 特质的定义和抽象类的定义很像,但它是使用
trait
关键字
语法
trait 名称 {
// 抽象字段
// 抽象方法
}
继承特质
- 使用
extends
来继承trait(scala不论是类还是特质,都是使用extends关键字)- 如果要继承多个trait,则使用
with
关键字
class 类 extends 特质1 with 特质2 {
// 字段实现
// 方法实现
}
继承单个trait 代码示例
object Test01 {
//定义一个 日志 特质
trait Logger {
//抽象方法 接收控制带
def log(message:String)
}
//定义一个控制台类 继承日志类 输出日志信息
class ConsoleLogger extends Logger {
override def log(message: String): Unit = println("控制台日志:\n" + message)
}
def main(args: Array[String]): Unit = {
val logger = new ConsoleLogger
logger.log("这是一条日志")
}
}
继承多个特质 代码示例
object Test02 {
//创建一个 消息发送 特质 添加 发送 方法
trait MessageSender {
//定义一个发送方法
def send(msg:String)
}
//创建一个 消息接收 特质 添加 接收 方法
trait MessageReceive {
def receive() : String
}
//创建 消息工作 类 实现 接收和发送两个特质
class MessageWorker extends MessageSender with MessageReceive {
//继承发送方法
override def send(msg: String): Unit = println(s"发送消息 : ${msg}")
//继承接收方法
override def receive(): String = "你好!我叫张三"
}
def main(args: Array[String]): Unit = {
val worker = new MessageWorker
//发送信息 hello
worker.send("hello")
//接收信息
println(worker.receive())
}
}
定义具体的方法
和类一样,trait中还可以定义具体的方法
代码示例
object Test03 {
trait LoggerDetail {
//在trait 中定义具体方法
def log(msg:String): Unit = println(s"msg = ${msg}")
}
class UserService extends LoggerDetail {
def add(): Unit = {
//调用log 方法
log("添加用户")
}
}
def main(args: Array[String]): Unit = {
val service = new UserService
//调用add方法
service.add()
}
}
trait中定义具体的字段和抽象的字段
定义
- 在trait中可以定义具体字段和抽象字段
- 继承trait的子类自动拥有trait中定义的字段
- 字段直接被添加到子类中
代码示例
object Test04 {
//定义 日志 特质
trait Logger {
//定义一个SimpleDateFormat字段,用来格式化日期(显示到时间)
val df = new SimpleDateFormat("yyyy-MM-dd HH:mm")
//创建一个log抽象方法,用于输出日志
def log(msg:String)
}
//创建ConsoleLogger类 转化当前时间并输出控制台信息
class ConsoleLogger extends Logger {
override def log(msg: String): Unit = {
println(s"${df.format(new Date)}\t控制台消息:\n${msg}")
}
}
def main(args: Array[String]): Unit = {
//创建对象
val logger = new ConsoleLogger
//调用方法
logger.log("NullPointerException")
}
}
模板模式
- 在一个特质中,具体方法依赖于抽象方法,而抽象方法可以放到继承trait的子类中实现,这种设计方式也称为模板模式
- 在scala中,trait是可以定义抽象方法,也可以定义具体方法的
- trait中定义了一个抽象方法
- trait中定义了其他的几个具体方法,会调用抽象方法
- 其他实现类可以来实现抽象方法
- 真正调用trait中具体方法的时候,其实会调用实现类的抽象方法实现
代码示例
object Test05 {
//定义一个 日志 特质
trait Logger {
//定义一个日志信息抽象方法
def log(msg:String)
//定义 info方法
def info(msg:String): Unit = log("INFO:" + msg)
//定义 warn 方法
def warn(msg:String): Unit = log("WARN:" + msg)
//定义 error 方法
def error(msg:String): Unit = log("ERROR:" + msg)
}
//定义控制台 输出日志
class ConsoleLogger extends Logger {
override def log(msg: String): Unit = {
println(msg)
}
}
def main(args: Array[String]): Unit = {
//创建对象
val logger = new ConsoleLogger
//调用方法
logger.info("信息日志")
logger.warn("警告日志")
logger.error("错误日志")
}
}
对象混入trait
scala中可以将trait混入到对象中,就是将trait中定义的方法、字段添加到一个对象中
语法
val/var 对象名 = new 类 with 特质
代码示例
object Test06 {
//定义一个日志 特质
trait Logger {
//输出日志的方法
def log(msg:String): Unit = println(msg)
}
class UserService
def main(args: Array[String]): Unit = {
val service = new UserService with Logger
service.log("混入的方法")
}
}
trait调用链
类继承了多个trait后,可以依次调用多个trait中的同一个方法,只要让多个trait中的同一个方法在最后都依次执行super关键字即可。类中调用多个tait中都有这个方法时,首先会从最右边的trait方法开始执行,然后依次往左执行,形成一个调用链条。
代码示例
object Test07 {
//定义一个 处理 特质
trait HandlerTrait {
//定义一个处理 方法
def handle(data:String): Unit = {
println("处理数据....")
}
}
//定义一个 数据验证的特质 继承 处理 特质
trait DataValidHandlerTrait extends HandlerTrait {
//重新处理 方法
override def handle(data:String): Unit = {
println("验证数据....")
super.handle(data)
}
}
//定义一个 签名校验 特质 继承处理特质
trait SignatureValidHandlerTrait extends HandlerTrait {
//重写处理方法
override def handle(data: String): Unit = {
println("效验签名...")
super.handle(data)
}
}
//定义一个支付 特质 继承 签名效验特质 和 数据验证特质
class PayService extends DataValidHandlerTrait with SignatureValidHandlerTrait {
//重写处理数据方法
override def handle(data: String): Unit = {
println("准备支付...")
super.handle(data)
}
}
def main(args: Array[String]): Unit = {
val service = new PayService
service.handle("支付参数")
}
}
trait的构造机制
- trait也有构造代码,但和类不一样,特质不能有构造器参数
- 每个特质只有**
一个无参数
**的构造器。- 一个类继承另一个类、以及多个trait,当创建该类的实例时,它的构造顺序如下:
- 执行父类的构造器
从左到右
依次执行trait的构造器- 如果trait有父trait,先构造父trait,如果多个trait有同样的父trait,则只初始化一次
- 执行子类构造器
代码示例
object Test08 {
trait Logger {
println("执行Logger构造器")
}
trait MyLogger extends Logger {
println("执行MyLogger构造器")
}
trait TimeLogger extends Logger {
println("执行TimeLogger构造器")
}
class Person {
println("执行Person构造器")
}
class Student extends Person with TimeLogger with MyLogger {
println("执行Student构造器")
}
def main(args: Array[String]): Unit = {
new Student
}
}
trait继承class
trait也可以继承class的。特质会将class中的成员都继承下来。
代码示例
object Test16 {
//创建一个MyUtils类,定义printMsg方法
class MyUtil {
def printMsg(msg:String): Unit = {
println(msg)
}
}
//创建一个Logger特质,继承自MyUtils,定义log方法
trait Logger extends MyUtil {
def log(msg:String): Unit = {
printMsg("Logger:" +msg)
}
}
//创建一个Person类 继承Logger类
class Person extends Logger {
//实现sayHello方法,调用log方法
def sayHello(): Unit = {
log("你好")
}
}
def main(args: Array[String]): Unit = {
val person = new Person
person.sayHello()
}
}