scala学习之旅(八):面向对象编程之trait

文章地址: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
  }
}

运行查看结果


scala学习之旅(八):面向对象编程之trait_第1张图片
这里写图片描述

但是父类的方法如果是抽象的话就不能调用 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 的类的父类
欢迎关注,更多福利


scala学习之旅(八):面向对象编程之trait_第2张图片
这里写图片描述

你可能感兴趣的:(scala学习之旅(八):面向对象编程之trait)