目录

  • ​​scala outline​​
  • ​​trait作用及代码演示​​
  • ​​trait 动态混入​​
  • ​​特质冲突​​
  • ​​特质叠加​​
  • ​​什么是特质叠加问题​​
  • ​​解决问题代码演示​​

scala outline

​​scala outline​​

trait作用及代码演示

trait作用

  1. Scala语言中,采用特质trait(特征)来代替java中接口的概念
  2. 对scala中只允许单继承机制的一种补充

trait 代码演示

​体会用trait实现以下功能​

a19_scala trait特质_抽象方法


基本语法

trait 特质名 {
代码主体
}

没有父类:class 类名 extends 特质1 with 特质2 with 特质3 …
有父类:class 类名 extends 父类 with 特质1 with 特质2 with 特质3…
object Test {
def main(args: Array[String]): Unit = {
val c = new C()
val e = new E()
c.getConnect() // 链接oracle数据库
e.getConnect() // 链接mysql数据库
}
}

trait Trait01 {
//定义一个规范
def getConnect(): Unit
}

class A {}

class B extends A {}

// 如果一个类在混入特质和继承父类时,应当把父类写在extends后
class C extends A with Trait01 {
override def getConnect(): Unit = {
println("链接oracle数据库...")
}
}

class D {}

class F extends D {}

class E extends D with Trait01 {
override def getConnect(): Unit = {
println("链接mysql数据库...")
}
}

注意事项

  1. 特质可以同时拥有抽象方法和具体方法,即非抽象方法
  2. 一个类可以混入多个特质
  3. 所有的Java接口都可以当做Scala特质使用

trait 动态混入

​作用:​​可灵活的扩展类的功能

object Test {
def main(args: Array[String]): Unit = {
val gir: Person = new Person

// 男人,需要购买保健品重振雄风,女人却不需要,所以单独为男人混入该特质,即动态混入特质
// 必须要加返回值类型 Person with C,不然boy对象不可以调用buy这个方法
val boy: Person = new Person with C {
override def buy(): Unit = {
println("男人专享:购买六味地黄丸,重振雄风")
}
}
}
}

// 定义跑步行为
trait A {
def run(): Unit
}

// 定义讲话行为
trait B {
def speak(): Unit
}

// 定义购买保健品行为
trait C {
def buy(): Unit
}

// 我们知道,人可以跑步,讲话,所以可以混入特质A、B,但是男人,需要购买保健品重振雄风,女人却不需要,所以不必混入特质C
class Person extends A with B {
override def run(): Unit = {
println("慢悠悠的跑步")
}

override def speak(): Unit = {
println("小心翼翼的讲情话")
}
}

特质冲突

  1. 一个类混入多个特质,多个特质之间有​​相同的抽象方法​​,特质之间没有关系,直接对抽象方法实现一次即可
object Test {
def main(args: Array[String]): Unit = {
val c: C = new C
c.f()
}
}

trait A {
// 抽象方法
def f(): Unit
}

trait B {
def f(): Unit
}

class C extends A with B {
override def f(): Unit = {
println("特质A、B的f方法,我谁都不用。我只把你们的方法重写,用我自己的")
}
}
  1. 一个类混入多个特质,多个特质之间有​​相同的非抽象方法​​,特质之间没有关系,应该对相同的非抽象方法进行重写
object Test {
def main(args: Array[String]): Unit = {
val c: C = new C
c.f()
}
}

// 非抽象方法
trait A {
def f(): Unit={
println("特质A")
}
}

trait B {
def f(): Unit={
println("特质B")
}
}

class C extends A with B {
override def f(): Unit = {
println("特质A、B的f方法,我谁都不用。我只把你们的方法重写,用我自己的")
}
}

特质叠加

什么是特质叠加问题

一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的非抽象方法,且两个trait混入相同的trait(TraitC)即及所谓的“钻石问题”,解决这类冲突问题,Scala采用了特质叠加的策略

a19_scala trait特质_抽象方法_02

​处理办法:​​ 加super.方法

解决问题代码演示

object Test {
def main(args: Array[String]): Unit = {
val sub: Sub = new Sub
println(sub.f()) // 输出结果 我的操作是--->向mysql中向hdfs中插入数据
}
}

trait C {
def f(): String = {
"插入数据"
}
}

trait A extends C {
override def f(): String = {
"向mysql中" + super.f()
}
}

trait B extends C {
override def f(): String = {
"向hdfs中" + super.f()
}
}

class Sub extends B with A {
override def f(): String = {
"我的操作是--->" + super.f()
}
}

上述案例中的super.f()调用的是父trait中的方法吗?

当一个类混入多个特质的时候,scala会对所有的特质及其父特质按照一定的顺序进行排序,而此案例中的super.f()调用的实际上是排好序后的下一个特质中的f()方法。排序规则如下:

  1. 第一步:列出混入的第一个特质B的混入关系,作为临时叠加顺序
  2. 第二步:列出混入的第二个特质A的混入关系,并将该顺序叠加到临时顺序前边,已经出现的特质不再重复

a19_scala trait特质_抽象方法_03

  1. 将子类Sub放在临时叠加顺序的第一个,得到最终的叠加顺序