1. Trait 基础
Scala Trait 用来定义一个抽象类,但和Java不同的是,用 Trait 定义的类中,既可以包含抽象字段、抽象方法,又可以包含具体字段和具体方法。
1.1 将trait作为接口使用
Scala 中的 Triat 是一种特殊的概念,首先我们可以将Trait作为接口来使用,此时的Triat 就与 Java 中的接口(implements) 非常类似。
在triat中可以定义抽象方法,就与抽象类中的抽象方法一样,只要不给出方法的具体实现即可。
类可以使用 extends 关键字继承 trait,注意,这里不是implements,而是extends,在scala中没有 implement 的概念,无论继承类还是 trait,统一都是 extends。
类继承 trait 后,必须实现其中的抽象方法,实现时不需要使用 override 关键字。
scala 不支持对类进行多继承,但是支持多重继承trait,使用 with 关键字即可。
下面看一个例子:
接口类 Person :
package cn.zyb
trait Person {
//定义两个抽象方法,并没有实现
def isMale: Boolean
def isYouth(age: Int): Boolean
}
接口类 BasketBallLover :
package cn.zyb
trait BasketBallLover {
def playBasketBall()
}
实现类:
package cn.zyb
//通过 with 来实现多继承
class YoungMan extends Person with BasketBallLover {
//实现 trait 中的抽象方法
//override 可以去掉,下面两个实现 就没有加 override
override def isMale: Boolean = true
def isYouth(age: Int): Boolean = age < 30
def playBasketBall(): Unit = println("走去打篮球!")
}
object YoungMan {
def main(args: Array[String]): Unit = {
val man = new YoungMan
println("我是纯爷们? " + man.isMale)
println("我是小鲜肉? " + man.isYouth(26))
man.playBasketBall()
}
}
运行结果:
我是纯爷们? true
我是小鲜肉? true
走去打篮球!
1.2 在 Trait 中定义抽象字段
在Trait中可以定义抽象字段,而 Trait 中的具体方法可以基于抽象字段来编写,但继承 Trait 的类,则必须覆盖抽象的field,提供具体的值。
trait Person {
val eyeNum: Int
def sayHello = {
println("我有 " + eyeNum + " 个眼!")
}
}
class YoungMan extends Person {
//此字段为 Trait 中的抽象字段,必须要声明,否则 IDE 会提示错误!
val eyeNum: Int = 2
}
object YoungMan {
def main(args: Array[String]): Unit = {
val man = new YoungMan
man.sayHello
}
}
结果:
我有 2 个眼!
1.3 在 trait 中定义具体方法 和 具体字段
Scala 中的 Triat 可以不是只定义抽象方法,还可以定义具体方法,即 trait 混入了类的功能。
Scala 还可以定义具体的字段。
trait Person {
//定义一个具体的字段
var eyeNum: Int = 2
//定义一个具体的方法
def breakOneEye = {
println("我要戳瞎我的 1 个眼!眼多 任性!咋地!")
eyeNum = eyeNum - 1
}
}
class YoungMan extends Person {
def sayHello = println("Hi, " + " 我有 " + eyeNum + " 个眼~")
}
object YoungMan {
def main(args: Array[String]): Unit = {
val man = new YoungMan
man.sayHello
man.breakOneEye
man.sayHello
}
}
结果:
Hi, 我有 2 个眼~
我要戳瞎我的 1 个眼!眼多 任性!咋地!
Hi, 我有 1 个眼~
2. Trait 进阶
2.1 为实例混入Trait
在创建某个类的对象时,可以指定该对象混入某个 Trait,这样只有这个对象混入了该 Trait,其他对象则没有
trait Person {
def sayHello = {
println("我有 2 个眼!")
}
}
object YoungMan {
def main(args: Array[String]): Unit = {
val man1 = new YoungMan with Person
man1.sayHello
//man2 没有 sayHello 方法
val man2 = new YoungMan
}
}
2.2 Trait调用链
在 Scala 中,支持让类继承多个 Trait(这多个 Trait 继承同一个 父Trait)依次调用多个 Trait中的同一个方法,只要让多个 Trait 中的同一个方法中,在最后都执行 super方法。
注意:在类中调用多个 Trait 中都有的方法时,首先会从最右边的
Trait 的方法开始执行,然后依次向左执行,形成一个调用条。这个相当于设计模式中的责任链模式的一种具体实现依赖。
下面把 Trait、class 等都写到一个文件中,是为了方便看,这样写是可以的。
package cn.zyb
trait Person {
//这里是一个具体方法
def sayHello() = println("我是个人!")
}
trait Man extends Person {
//子类想再次实现 父类中的具体方法,必须添加 override 关键字
//如果子类想实现 父类中的抽象方法,则override 不是必须的。
override def sayHello() = {
println("我还是个纯爷们!")
super.sayHello()
}
}
trait WoMan extends Person {
override def sayHello() = {
println("我是个女王!")
super.sayHello()
}
}
//类 LadyBoy 继承了 Man 和 Woman
class LadyBoy extends Man with WoMan {
sayHello()
}
object LadyBoy {
def main(args: Array[String]): Unit = {
new LadyBoy()
println("不好意思,我其实是个人妖……")
}
}
运行结果为:
我是个女王!
我还是个纯爷们!
我是个人!
不好意思,我其实是个人妖……
混合使用Trait 的具体方法和抽象
Trait 的具体方法可以调用 Trait的抽象方法,然后 Trait 的抽象方法 在 Trait 的子类中实现。
package cn.zyb
trait Person {
//这里是一个抽象方法
def getAge: Int
//这是一个具体方法
def sayHello() = println("I'm " + getAge + " years old.")
}
class Boy(age: Int) extends Person {
def getAge = age
sayHello()
}
object Boy{
def main(args: Array[String]): Unit = {
new Boy(26)
}
}
结果为:
I'm 26 years old.
2.3 Trait构造机制
在Scala中,Trait是有构造代码的,就是Trait中不包含在任何方法中的代码,而继承了Trait的构造机制如下:
- 父类的构造函数
- Trait的构造代码执行,多个Trait从左向右依次执行
- 构造Trait时会先构造父Trait,如果多个Trait继承同一个父Trait,则父Trait只会构造一次
- 所有trait构造结束之后,子类的构造函数执行
package cn.zyb
trait Person {
println("this is Person")
}
trait Clothes {
println("this is Clothes ")
}
trait Skirt extends Clothes {
println("this is Skirt ")
}
trait Shorts extends Clothes {
println("this is Shorts ")
}
class Woman extends Person with Skirt with Shorts {
println("this is Woman ")
}
object Woman {
def main(args: Array[String]): Unit = {
new Woman
}
}
结果为:
this is Person
this is Clothes
this is Skirt
this is Shorts
this is Woman
疑问:
def 后面到底 跟不跟 = 号?
确定了,def 后面可以跟,也可以不跟,具体参考:https://blog.csdn.net/zhu_si_tao/article/details/76412057