说明
- 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,不是表示其父特质对象,而是表示上述叠加顺序中的下一个特质。