天天看点

scala基础之特质trait一 特质用作接口二 使用特制中的抽象字段和实际子段三 像Java抽象类一样使用特质四 简单混入特质五 通过继承来限制特质的使用范围六 限定特质只可用于指定类型的子类七 保证特质只能被添加到只有一个特定方法的类型八 为对象实例添加特质九 向特质一样继承Java接口

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("奔跑中.....")
    }
}