Scala中特质的使用以及特质冲突

Scala 中的特质类似于接口,可包含抽象和非抽象成员,允许类多重混入。文章通过示例介绍了如何混入单个和多个特质,处理特质冲突以及探讨了特质的叠加问题(钻石问题),并展示了具体的执行顺序。

说明

  • Scala语言中,采用特质trait来代替接口的概念。也就是说,多个类中,具有相同的特征时,可以将此特征独立出来,采用trait关键字声明。
  • Scala特质中,既可以有抽象属性和抽象方法,也可以有非抽象属性和非抽象方法。
  • 一个类可以混入多个特质。

混入单特质

object Scala03_Trait {
  def main(args: Array[String]): Unit = {
    val stu:PersonTrait03 = new Student03
    stu.sleep()
    stu.eat()
    println(stu.name)
  }
}


trait PersonTrait03 {
  // 特质中既可以有抽象属性和抽象方法
  var name: String
  def sleep(): Unit

  // 也可以有非抽象属性和非抽象方法
  var age: Int = 18
  def eat(): Unit = {
    println("Person eat")
  }
}

// 混入特质
class Student03 extends PersonTrait03 {

  // 重写特质中的抽象方法和属性
  override var name: String = "Li Ming"

  override def sleep(): Unit = {
    println("Student sleep")
  }
}

混入多个特质

  • 没有类继承的混入多个特质:extends trait1 with trait2 with …
  • 有类继承的混入多个特质,先继承类,再混入特质:extends ClassName with trait1 with trait2 …
  • 创建对象时,动态混入特质:new ClassName with trait1 {重写抽象方法}。
object Scala04_Trait {
  def main(args: Array[String]): Unit = {
    /*val clzz = new MyClass04
    clzz.mA()
    val clazz1 = new MyClass004
    clazz1.mB()*/

    // 动态的混入特质
    val clzz004 = new MyClass004 with TraitC {
      override def mC(): Unit = {
        println("mC")
      }
    }
    clzz004.mC()
  }
}

trait TraitA {
  def mA(): Unit
}

trait TraitB {
  def mB(): Unit
}

trait TraitC {
  def mC(): Unit
}

class Super {
}

// 没有类继承的混入多个特质
class MyClass04 extends TraitA with TraitB with TraitC {
  override def mA(): Unit = {
    println("mA")
  }

  override def mB(): Unit = {
    println("mB")
  }

  override def mC(): Unit = {
    println("mC")
  }
}

// 有继承,混入多个特质。继承的类放在第一个位置
class MyClass004 extends Super with TraitA with TraitB{
  override def mA(): Unit = {
    println("mA")
  }

  override def mB(): Unit = {
    println("mB")
  }

}

特质冲突(普通冲突)

  • 当一个类混入多个特质时,如果两个特质之间没有关系,但是有同名的抽象方法,需要重写抽象方法。
  • 当一个类混入多个特质时,如果两个特质之间没有关系,但是有同名的非抽象方法,需要重写非抽象方法。
object Scala05_Trait {
  def main(args: Array[String]): Unit = {
    val p = new Person05
    p.m1()

    val p2 = new Person005
    p2.m1()
  }
}

trait Person05TraitA {
  def m1(): Unit
}

trait Person05TraitB {
  def m1(): Unit
}

class Person05 extends Person05TraitA with Person05TraitB {
  override def m1(): Unit = {
    println("Person05中重写的m1方法")
  }
}

trait Person005TraitA {
  def m1(): Unit = {
    println("Person005TraitA m1")
  }
}

trait Person005TraitB {
  def m1(): Unit = {
    println("Person005TraitA m1")
  }
}

class Person005 extends Person005TraitA with Person005TraitB {
  override def m1(): Unit = {
    println("Person005中重写的m1方法")
  }
}

特质叠加(钻石问题)

在这里插入图片描述

说明

特质A和特质B分别混入了特质C,特质A和特质B都重写了特质C中的m1方法。一个类同时混入特征A和特征B,那么这个类中的m1方法执行时是哪个方法呢?这就是钻石问题。

代码

object Scala06_Trait {
  def main(args: Array[String]): Unit = {
    val operation = new MyOperation
    println(operation.m1())		// 我的操作是:向HDFS向数据库插入数据
  }
}

trait Operation {
  def m1(): String = {
    "插入数据"
  }
}

trait DBOperation extends Operation {
  override def m1(): String = {
    "向数据库" + super.m1()  }
}

trait HDFSOperation extends Operation {
  override def m1(): String = {
    "向HDFS" + super.m1()
  }
}

class MyOperation extends DBOperation with HDFSOperation with Operation {
  override def m1(): String = {
    "我的操作是:" + super.m1()
  }
}

执行结果解析

  • 第一步:列出混入的第一个特质的继承关系,作为临时顺序。
    DBOperation --> Operation
  • 第二步:列出第二个特质的继承关系,并将该顺序叠加到第一个特质的顺序之前。需要注意的是,已经出现的特质不再重复。
    HDFSOperation --> DBOperation --> Operation
  • 第三步:将子类放在临时叠加顺序的第一个,为最终叠加顺序。
    MyOperation --> HDFSOperation --> DBOperation --> Operation

注意:案例中的super,不是表示其父特质对象,而是表示上述叠加顺序中的下一个特质。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值