文章地址:http://www.haha174.top/article/details/258129
1 概念
Scala 中的triat 是一种特殊的概念
首先我们可以将trait作为接口来使用,此时的triat 和java 中的接口非常相似
在trait 中可以定义抽象方法,就与抽象类中的抽象方法一样,只要不给出方法的具体实现即可。
类中可以使用extends 关键字集成trait 注意,这里不是implements ,而是extends 在scala中没有implements 这个概念,无论集成还是trait 统一都是extends .
类集成trait 后必须实现其中的抽象方法实现的时候不需要override关键字
scala 不支持对类多继承但支持对trait 多继承 ,但支持多重继承trait ,使用with 关键字即可。
trait HelloTrait {
def sayHello(name:String)
}
trait MakeFriendsTrait {
def makeFriends(p:Persion)
}
class TraitDemo(var name:String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable {
def sayHello(name: String): Unit = println(name)
def makeFriends(p: Persion): Unit = println(p.getName())
}
2.在trait中定义具体的方法
scala 的trait 可以不是只定义抽象方法,还可以定义具体的方法,此时trait 更像是包含了通过用工具方法的东西
有一个专有名词来解释这种情况就是说,trait 的功能混入了类
//举例来说,trait 中可以包含一些很多类都通用的功能方法,比如打印日志等等,spark 中就使用了trait 来定义了通用的日志打印方法。
例如
trait LoggerTrait {
def info(message:String)=println(message)
}
class TraitDemo(var name:String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable with LoggerTrait {
def sayHello(name: String): Unit = println(name)
def makeFriends(p: Persion): Unit = println(p.getName())
info("logger trait")
}
3.在trait中定义字段
scala 中的trait 就可以定义具体的field ,此时继承trait 的类就自动获得了trait 中定义的field
但是这种获取field 的方式与继承class 是不同的:如果是继承class 获取的field ,实际是定义在父类中的而继承trait 获取的field ,就直接被添加到了类中。
还可以定义抽象的字段但是继承得类需要提供具体的值
trait FieldTrait{
val num:Int=2
var abnu:String
}
class TraitDemo(var name:String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable with LoggerTrait with FieldTrait{
def sayHello(name: String): Unit = println(name)
def makeFriends(p: Persion): Unit = println(p.getName())
var abnu: String = "hello"
info("FieldTrait value:"+num+"abnu:"+abnu)
}
4.trait调用链
scala 中支持让类继承多个trait 后,依次调用多个trait 的同一个方法,只要让多个trait 的同一个方法中在最后都执行super 方法即可,
类中调用多个trait 都有的这个方法时,首先会从最右边的trait 开始执行,然后依次向左执行形成一个调用链条,这种特性什么强大,其实就相当于设计模式的责任链模式的一种具体的实现依赖。
trait DataValidHandler extends Handler{
override def handler(data:String): Unit ={
println("check data"+data)
super.handler(data)
}
}
trait SignatureHandler extends Handler{
override def handler(data:String): Unit ={
println("check sig"+data)
super.handler(data)
}
}
class PersionTrait(var name:String) extends SignatureHandler with DataValidHandler {
def sayHello: Unit ={
println("hello"+name)
handler(name);
}
}
object DemoTrait{
def main(args: Array[String]): Unit = {
var persionTrait =new PersionTrait("haha")
persionTrait.sayHello
}
}
运行查看结果
但是父类的方法如果是抽象的话就不能调用 super.handler(data) 不然会编译报错
5.trait 构造机制
在scala中,trait 也是有构造代码的,也是trait 的,不包含在任何方法中的代码
而继承了trait 的类的构造机制如下:
1 父类的构造函数执行
2 多个trait从左到右依次执行
3 构造trait 时会构造父trait 如果多个trait 继承同一个父trait 则trait 只会构造依次
4所有 trait 构造完毕之后子类的构造函数执行
6.trait field 的初始化
在scala trait 是没有接收参数的构造函数的,这个trait 和class 的唯一区别,但那时如果需求就是要trait 能够对field 进行初始化,该怎么办?只能使用scala 中 非常特殊的一种高级特性–提前定义
class Persion extends {val msg:String="int"} with SayHello{}
另一种就是使用lazy value.
7.trait 继承class
在scala 中 trait 也可以继承自class ,此时这个class 就会成为所有继承该trait 的类的父类