Scala-特质

特质

特质的混入用法

特质的叠加

特质和抽象类的区别

特质自身类型


特质

  • Scala 语言中,采用特质 trait(特征)来代替接口的概念,也就是说,多个类具有相同 的特质(特征)时,就可以将这个特质(特征)独立出来,采用关键字 trait 声明。
  • Scala 中的 trait 中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可 以混入(mixin)多个特质。
  • 这种感觉类似于 Java 中的抽象类。 Scala 引入 trait 特征,第一可以替代 Java 的接口,第二个也是对单继承机制的一种 
trait 特质名 {
trait 主体
}

一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素, 所以在使用时,也采用了 extends 关键字,如果有多个特质或存在父类,那么需要采用 with 关键字连接。

没有父类:class 类名 extends 特质 1 with 特质 2 with 特质 3 …
有父类:class 类名 extends 父类 with 特质 1 with 特质 2 with 特质 3
  1. 类和特质的关系:使用继承的关系。
  2. 当一个类去继承特质时,第一个连接词是 extends,后面是 with。
  3. 如果一个类在同时继承特质和父类时,应当把父类写在 extends 后。

当父类和特质定义相同属性发生冲突时出现如下报错提示 则需要重写父类和特质的冲突属性 

object traits {
  def main(args: Array[String]): Unit = {
    //测试
    val st = new z
    st.hello()
    st.Run()
    st.study()

  }
}
//定义父类
class S{
  val name : String = "s"
  var age : Int = 20
  def hello(): Unit ={
    println("hello"+name)
  }
}

//定义特质
trait Young{
  //声明抽象和非抽象属性
  var age : Int
  val name : String = "young"

  //声明抽象和非抽象方法
  def play(): Unit ={
    println("playing games")
  }
  def Run(): Unit
}

//定义子类
class z extends S with Young {
  //重写冲突属性
  override val name : String = "zz"
  //重写特质抽象方法
  override def Run(): Unit = {
    println(s"${name}跑步")
  }
  //重写父类方法
  override def hello(): Unit = {
    super.hello()
    println("你好")
  }

  //定义子类方法
  def study(): Unit ={
    println(" 学习")
  }
}

 特质的混入用法

混入是可灵活的扩展类的功能

动态混入:创建对象时混入 trait,而无需使类混入该 trait

如果混入的 trait 中有未实现的方法,则需要实现

object traits {
  def main(args: Array[String]): Unit = {
    //测试
    val  st = new Ta
    st.study()
    st.increase()
    st.play()
    st.increase()
    println("------------------------------------------------")
    //动态混入
    val st2 = new Ta with Take {
      //重写特质3抽象类
      override def Singing(): Unit = println("唱歌")
      override def dancing(): Unit = println("跳舞")
    }
    st2.hello()
    st2.play()
    st2.Singing()
    st2.dancing()
    st2.increase()
  }
}
//定义父类
class S{
  val name : String = "s"
  var age : Int = 20
  def hello(): Unit ={
    println("hello"+name)
  }
}

//定义特质1
trait Young{
  //声明抽象和非抽象属性
  var age : Int
  val name : String = "young"

  //声明抽象和非抽象方法
  def play(): Unit ={
    println("playing games")
  }
  def Run(): Unit
}
//定义特质2
trait Knowledge{
  var amount: Int = 0
  def increase(): Unit
}

//定义特质用于动态混入
trait Take{
  def Singing(): Unit
  def dancing(): Unit
}

//定义混入特质类
class Ta extends S with Young with Knowledge {
  //重写冲突属性
  override val name: String = "zz"
  //重写S父类方法
  override def hello(): Unit = {
    super.hello()
    println("你好")
  }
  //定义子类方法
  def study(): Unit = {
    println(" 学习")
  }
  //重写Young特质抽象方法
  override def Run(): Unit = {
    println(s"${name}跑步")
  }
  //重写Knowledge特质抽象方法
  override def increase(): Unit = {
    amount += 1
    println(name+" :"+amount)
  }
}

特质的叠加

所谓的特质叠加,就是将混入的多个 trait 中的冲突方法叠加起来。

由于一个类可以混入(mixin)多个 trait,且 trait 中可以有具体的属性和方法,若混入 的特质中具有相同的方法(方法名,参数列表,返回值均相同),必然会出现继承冲突问题。 冲突分为以下两种:

  • 第一种,一个类(Sub)混入的两个 trait(TraitA,TraitB)中具有相同的具体方法,且 两个 trait 之间没有任何关系,解决这类冲突问题,直接在类(Sub)中重写冲突方法。

object traits {
  def main(args: Array[String]): Unit = {
    //测试
    val stt1 = new studentz
    stt1.increase()
  }
}
//定义特质1
trait Knowledge{
  var amount: Int = 0
  def increase(): Unit = {
    println("---->")
  }
}

//定义特质2
trait Take{
  def Singing(): Unit
  def dancing(): Unit
  def increase(): Unit = {
    println("<----")
  }
}
//定义父类
class S{
  val name : String = "s"
  var age : Int = 20
  def hello(): Unit ={
    println("hello"+name)
  }
  def increase(): Unit = {
    println("<------>")
  }
}
//定义叠加特质类
class studentz extends S with Knowledge with Take{
  //重写特质抽象方法
  override def Singing(): Unit = println("唱歌")
  override def dancing(): Unit = println("跳舞")

  override def increase(): Unit ={
    super.increase()
  }
}

  •  第二种,一个类(Sub)混入的两个 trait(TraitA,TraitB)中具有相同的具体方法,且 两个 trait 继承自相同的 trait(TraitC),及所谓的“钻石问题”,解决这类冲突问题,Scala 采用了特质叠加的策略。

object traits {
  def main(args: Array[String]): Unit = {
    //测试
    val my = new My
    println(my.describe())
  }
}
//定义super特质
trait A{
  def describe(): String = "AAAA"
}
//定义super特质的子特质1
trait B extends A{
  var b : String = "b"
  //重写特质super抽象方法
  override def describe(): String = super.describe()+b
}

//定义super特质的子特质2
trait C extends A {
  var c : String = "c"
  //重写特质super抽象方法
  override def describe(): String = super.describe()+c
}

//定义叠加特质类
class My extends B with C {
  //重写特质抽象方法
  override def describe(): String = super.describe()
}

 class My extends B with C

叠加顺序 C+B+A

  • 如果想要调用某个指定的混入特质中的方法,可以增加约束:super[],例如:

 特质和抽象类的区别

  1. 优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。
  2. 如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数, 而特质不行(有无参构造)。

特质自身类型

_: 类型名称 =>

使用this.属性 或 类名.属性 可直接访问 

自身类型可实现依赖注入的功能。

object traits {
  def main(args: Array[String]): Unit = {
    //测试
    val user = new RegisterUser("name","password")
    user.insert()
  }
}
//定义用户类
class User(val name : String,val password : String)//没主体可省略花括号不写

trait UserDao{
  //定义自身类型
  _: User =>
  //向数据库插入数据
  def insert(): Unit ={
    println(s"insert into db :${this.name}")
  }
}

//定义子类注册用户类                                             继承父类属性            混入特质
class RegisterUser(name : String , password : String) extends User(name,password) with UserDao

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

open_test01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值