参考文档
https://www.cnblogs.com/nowgood/p/scalatrait.html
Scala 中没有接口这样的概念,但是Scala 中有一种特殊类型的类,我们称其为特质。特质具有Java接口所具有的特性,除此之外,还具有一些Java接口不具备的特质。下面请跟随本篇文章踏入 Scala 特质的学习。
1.什么是Scala特质
2.特质的基本语法
3.特质的构造顺序
4.混入特质的语法
5.混入特质的执行顺序
6.限制特质的使用场景
1.什么是Scala特质
Scala 中不存在多继承,Scala 中只有单继承的方式。但是Scala 跟Java一样,可以通过混入多个接口达到近似的功能。
Scala的特质主要有以下几个特点
.1 Scala 中的特质主要用来定义接口,Scala 中的接定义与Java类似。
def CC: String
def QC(name: String): Unit
.2 除了基础的定义接口外,Scala 中的特质也允许存在非接口函数,这个特性跟Java8的扩展比较相似
.3 通过继承关系,限制特质的使用范围
.4 限制Scala 中的特质范围
1)限制特质只用于指定类型的子类
2)保证特质只能被添加到一个特定方法的类型,(实现该特制的类,必须具有某种结构 (如是否具有某个方法))
2.特质的基本语法
Trait中方法定义
scala 的特质主要使用 trait 进行定义。
定义的方式如下:
trait TestTrait {
def CC: String
def QC(name: String): Unit
}
CC 方法:不接受任何参数,返回值为String
QC 方法:方法接受一个name 参数,无返回值
实现方法:
class XXC extends TestTrait {
override def CC: String = "ccc"
override def QC(name: String): Unit = println(s"${name}")
}
Trait中字段定义
如果在特质中定义字段,
必须在继承的具体类中实现(不需要 override 关键字),除了继承类为 abstract class (抽象类),不需要实现。
trait TestTrait2 {
var userName: String
val password: String
}
abstract class Trait2Imp extends TestTrait2 {
var userName: String = "username"
}
带有具体方法的特质
scala 中的特质可以有具体的方法,示例如下
package traitCode
/**
* Created by szh on 2018/12/25.
*/
trait TestTrait3 {
def impMethod: String = {
"this is a method"
}
def queryCC: Unit
}
class Trait3Imp extends TestTrait3 {
override def queryCC: Unit = {
println("ccccc")
}
}
object Trait3ImpObj extends App {
val d = new Trait3Imp()
d.queryCC
println(d.impMethod)
}
但是,需要注意
让特质混有具体行为有一个弊端. 当特质改变时, 所有混入该特质的类都必须重新编译.
3.特质的构造顺序
特质也可以有构造器,由字段的初始化和其他特质体中的语句构成。这些语句在任何混入该特质的对象在构造时都会被执行。
构造器的执行顺序:
- 调用超类的构造器;
- 特质构造器在超类构造器之后、类构造器之前执行;
- 特质由左到右被构造;
- 每个特质当中,父特质先被构造;
- 如果多个特质共有一个父特质,父特质不会被重复构造
- 所有特质被构造完毕,子类被构造。
4.混入特质的基本语法
混入特质有2个时机
1.类声明/实现 的阶段
2.声明实例的阶段
特质定义:
trait MultiTrait {
def Multi1(name: String): Unit
}
trait MultiTrait2 {
def Multi2(name: String): Unit
}
trait MultiTrait3 {
def Multi3(name: String): Unit
}
1.类声明/实现 的阶段
class ImpMultiTrait extends MultiTrait with MultiTrait2{
override def Multi1(name: String): Unit = {
println(s"multi1 ${name}")
}
override def Multi2(name: String): Unit = {
println(s"mulit2 ${name}")
}
}
2.声明实例的阶段
val f = new ImpMultiTrait with MultiTrait3 {
override def Multi3(name: String): Unit = println("++++++")
}
f.Multi3("cccc")
特别注意 :
整体代码
package traitCode
/**
* Created by szh on 2018/12/25.
*/
trait MultiTrait {
def Multi1(name: String): Unit
}
trait MultiTrait2 {
def Multi2(name: String): Unit
}
trait MultiTrait3 {
def Multi3(name: String): Unit
}
class ImpMultiTrait extends MultiTrait with MultiTrait2{
override def Multi1(name: String): Unit = {
println(s"multi1 ${name}")
}
override def Multi2(name: String): Unit = {
println(s"mulit2 ${name}")
}
}
object ImpMultiTraitMain extends App{
val d = new ImpMultiTrait()
d.Multi1("hahaha")
d.Multi2("hahaha")
val f = new ImpMultiTrait with MultiTrait3 {
override def Multi3(name: String): Unit = println("++++++")
}
f.Multi3("cccc")
}
5.混入特质的执行顺序问题
特质可以将对象原本没有的方法与字段加入对象中
如果特质和对象改写了同一超类的方法, 则排在右边的先被执行.
abstract class Feline {
def say()
}
trait Tiger extends Feline {
// 在特质中重写抽象方法, 需要在方法前添加 abstract override 2个关键字
abstract override def say() = println("嗷嗷嗷")
def king() = println("I'm king of here")
}
class Cat extends Feline {
override def say() = println("喵喵喵")
}
object Test extends App {
val feline = new Cat with Tiger
feline.say // Cat 和 Tiger 都与 say 方法, 调用时从右往左调用, 是 Tiger 在叫
feline.king // 可以看到即使没有 cat 中没有 king 方法, Tiger 特质也能将自己的方法混入 Cat 中
}
输出:
嗷嗷嗷
I'm king of here
6.限制特质的使用场景
我们可以限制特质的使用
主要分为以下两种类型
1.通过继承关系限制
2.通过结构化进行限制
i.限制继承结构
ii.限制方法结构
1.通过继承关系限制
此种方法较少使用,
主要语法如下:
trait [TraitName] extends [SuperThing]
含义如下:
此 TraitName 只可以被混入到继承了SuperThing的类中,这个SuperThing可以是特质,类或者抽象类。
示例
trait TQTrait extends SuperThing {
def Fun1: Unit
}
class WF extends MultiTrait with TQTrait{
override def Fun1: Unit = {
println("WCG")
}
override def Multi1(name: String): Unit = println("name")
}
object WF extends App{
val f = new WF
f.Fun1
}
Error:(12, 34) illegal inheritance; superclass Object
is not a subclass of the superclass SuperThing
of the mixin trait TQTrait
class WF extends MultiTrait with TQTrait{
2.通过结构化进行限制
这个方案主要用到了自身类型(Self Type),Scala 中对于自身类型的描述如下:
任何具体类混入特质的时候,必须保证他的类型和特质的自身类型一致。
i.限制继承结构
为了让特质必须继承 一个类 或者 该类的子类,我们可以进行如下的定义。
trait LimitTrait1 {
this : SuperThing =>
def betterThing
}
以上定义表示,LimitTrait 的实现类,必须继承自 SuperThing。
完整代码:
package traitCode
/**
* Created by szh on 2018/12/25.
*/
trait LimitTrait1 {
this : SuperThing =>
def betterThing
}
class PrintOff extends LimitTrait1 {
override def betterThing: Unit = {
println("Just do better")
}
}
object LimitTraitMain extends App {
val c = new PrintOff
c.betterThing
}
出错:
ii.限制方法结构
此种方法主要用于限制继承接口的类必须含有某种方法。
示例如下:
trait LimitTrait3 {
this: {
def speak: Unit
def superMan: Unit
} =>
}
完整代码:
package traitCode
/**
* Created by szh on 2018/12/25.
*/
trait LimitTrait3 {
this: {
def speak: Unit
def superMan: Unit
} =>
}
class LimitTestMain extends LimitTrait3 {
def speak: Unit = {
println("zzzzzzzzzzzzzzzzzz")
}
def superMan: Unit = {
println("yyyyyyyyyyyyyyyy")
}
}
object LimitTestMain extends App{
val f = new LimitTestMain
f.speak
f.superMan
}
如果不实现以上方法,会报错: