Scala中,trait相当于Java中的接口,遇到需要使用Java接口的场景时,你就在Scala中可以使用trait了。
我们知道Java中你可以实现多个接口,那么Scala中,你也可以继承多个trait
Java中接口不能有自己的实现方法,但是Scala中trait可以包含自己的实现方法
一 特质用作接口
接口的作用:对行为进行规范,具有解耦的作用,满足业务系统依赖倒置的设计原则
注意:
第一:如果只需要一个那么使用extends,要实现多个trait,需要使用with
第二:抽象类继承trait,可以不给具体的实现,实现可以交给子类去做
trait BaseSoundPlayer {
def play(music:String)
def close
def puase(music:String,time:Int)
def stop
def resume
}
trait BaseVedioPlayer {
def display(vedio:String)
}
class MP4SoundPlayer extends BaseSoundPlayer with BaseVedioPlayer{
override def play(music: String): Unit = {
println("playing music "+music)
}
override def stop: Unit = {
println("stop to play")
}
override def puase(music: String, time: Int): Unit = {
println("pause to play music "+music+" for "+time+" s")
}
override def close: Unit = {
println("closed player")
}
override def resume: Unit = {
println("resume to play")
}
override def display(vedio: String): Unit = {
println("this player also watch the vedio "+vedio)
}
}
abstract class BasePlayer extends BaseSoundPlayer with BaseVedioPlayer{
}
二 使用特制中的抽象字段和实际子段
在特质中定义抽象字段和实际子段,以便于继承该特质的类都可以使用这些字段
声明一个变量,赋一个初始值,就是一个实际字段,否则这个字段就是抽象字段
注意:
# 抽象字段不需要加override,而且变量修饰符应该和trait一样,因为trait不会针对抽象字段产生get set方法,所以子类就需要提供变量修饰符
# 实际字段如果是var变量,不需要加override关键字,那么子类重写不需要加变量修饰符,因为本身这个字段就有set方法,所以可以子类就可以直接修改
# 实际子段如果是val变量,需要加override关键字,那么子类重写必须加上变量修饰符,因为trait中的该字段没有set方法,如果你想改变这个值,就相当于你要在子类重新写一个,所以需要加override
trait PizzaTrait {
/*抽象字段*/
var numToppings:Int
val ptype:String
/*实际字段*/
var size = 14
val maxNumToppings = 10
}
class Pizza extends PizzaTrait{
/*抽象字段不需要加override,而且变量修饰符应该和trait一样*/
var numToppings: Int = 4
val ptype: String = "thin"
/*实际字段不需要加override,而且不需要加变量修饰符*/
size = 16
override val maxNumToppings = 20
}
三 像Java抽象类一样使用特质
抽象类:可以有抽象字段和抽象方法,也可以有非抽象字段和非抽象方法
注意:
如果一个继承了特质,但是并没有实现其抽象字段或者抽象方法,那么该类必须加abstract字段,意思就是说这个类必须为抽象类
trait Pet {
var weight:Float
def speakTo(who:String,sound:String){println("Towards "+who+", "+sound)}
def actingCute
}
case class Cat(name:String) extends Pet{
var color:String = ""
var weight: Float = 0.0f
def this(cname:String,color:String,weight:Float){
this(cname)
this.color = color
this.weight = weight
}
override def actingCute: Unit = {
println(s"$name is acting cute");
}
def desc(): Unit = {
println(s"I'm $name, my color is $color")
}
}
case class Dog(name:String) extends Pet{
var ptype:String = ""
var weight: Float = 0.0f
def this(dname:String,ptype:String,weight:Float){
this(dname)
this.ptype = ptype
this.weight = weight
}
override def actingCute: Unit = {
println(s"$name is acting cute");
}
def desc(): Unit = {
println(s"I'm $name, my belongs to $ptype")
}
}
四 简单混入特质
说的明白些:其实就是继承抽象类并且混入withtrait
类似于Java中一个类继承了抽象类,实现了某一个接口
五 通过继承来限制特质的使用范围
特质可以限定哪些类来使用是可以的,比如说限定某些继承了某个类或者某个特质的类来使用这个trait
语法格式:
trait [traitname] extends [superthings]
一般情况下,某一个类可以随便继承其他父类,和混入其他的trait,但是有的时候,你只希望混入继承了该父类的trait才可以混入,否则混入不进来,这也就是限制了不能随意的混入
class StarfleetComponent
class RomulanStuff
trait StarfleetWrapCore1 extends StarfleetComponent
class Starship extends StarfleetComponent with StarfleetWrapCore1
//编译报错,因为StarfleetWrapCore 没有继承RomulanStuff
class Warbird1 extends RomulanStuff with StarfleetWrapCore1
/*如果我们这样修改就没有问题了*/
trait StarfleetWrapCore2 extends RomulanStuff
class Warbird2 extends RomulanStuff with StarfleetWrapCore2
六 限定特质只可用于指定类型的子类
通过语法this:指定类型 => 然后指定所允许混入的类或者其子类才可以混入该trait
class BaseType
class ParentType
trait MyTrait {
/**
* 指定该trait只能被BaseType的子类可以混入
* 不是BaseType的子类是不可以混入这个trait的
*/
this:BaseType =>
}
class ConcreteType extends BaseType with MyTrait
/*所以这里会报错*/
class ImplementType extends ParentType with MyTrait
七 保证特质只能被添加到只有一个特定方法的类型
允许特质混入到一个有给定签名的方法的类型(类,抽象类或者特质)
解决办法:
trait 特质名字{
this:{def 函数名(参数:数据类型):返回值类型} =>
}
trait Limit {
this:{ def validate(passwd:String):Boolean} =>
}
class Define extends Limit{
//必须有这样的方法签名才可以混入Limit特质
def validate(passwd:String):Boolean = {
true
}
}
八 为对象实例添加特质
有时候,我们可能只是想给某些对象添加特质,而不是针对类,即基于该类的对象,有的可以添加特质,有的不可以
语法格式:
new 类名字 with trait名字
class DavidBanner
trait Angry{
println("You won't like me ...")
}
object Test extends App{
val hunk = new DavidBanner with Angry
}
九 向特质一样继承Java接口
Scala中,我们可以像继承特质一样继承Java接口,通过with可以多继承,然后在类中实现java接口的方法
public interface Animal {
public void speak();
}
public interface Wagging {
public void wag();
}
public interface Running {
public void run();
}
class Tiger extends Animal with Wagging with Running{
override def speak(): Unit = {
println("吼吼")
}
override def wag(): Unit = {
println("摇尾巴")
}
override def run(): Unit = {
println("奔跑中.....")
}
}