Scala之特质特质Trait

15 篇文章 0 订阅

Scala之特质特质Trait

一、概述

Scala语言中,采用特质trait(特征)来代替接口的概念,也就是说,多个类具有相同的特征(特征)时,就可以将这个特质(特征)独立出来,采用关键字trait声明。
Scala中的trait中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可以混入(mixin)多个特质。
Scala引入trait特征,第一可以替代Java的接口,第二个也是对单继承机制的一种补充。

二、特质声明

1)基本语法

trait 特质名 {
	trait体
}

2)案例实操

trait PersonTrait {

    // 声明属性
    var name:String = _

    // 声明方法
    def eat():Unit={

    }

    // 抽象属性
    var age:Int
    
    // 抽象方法
    def say():Unit
}

三、特质基本语法

一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素,所以在使用时,也采用了extends关键字,如果有多个特质或存在父类,那么需要采用with关键字连接。

1)基本语法:

没有父类:class  类名 extends  特质1   with    特质2   with   特质3 …
有父类:class  类名  extends  父类   with  特质1   with   特质2  with 特质3…

2)说明

(1)类和特质的关系:使用继承的关系。
(2)当一个类去继承特质时,第一个连接词是extends,后面是with。
(3)如果一个类在继承特质和父类时,应当把父类写在extends后。

3)案例实操

package com.scala.charpter06

object Triat_test {
  
  class Animal
  
  trait Logger{
    //具体属性
    val name = "zahngsan" 
    //抽象属性
    val age:Int
    //具体方法
    def m1(x:Int,y:Int) = x+y
    //抽象方法
    def printMag:Unit
  }
  
  trait Logger2
  
  //子类不需要继承父class时,extends用于实现第一个trait,后续实现其他trait使用with关键字
  class WarnLogger extends Logger with Logger2{
    
    override val age: Int =20
  
    override def printMag: Unit = println("WarnLogger.....")
    
  }
  
  子类需要继承父class时,extends用于继承trait,后续实现其他trait使用with关键字
  class ErrorLogger extends Animal with Logger with Logger2{
    
    override val age: Int = 400
  
    override def printMag: Unit = println("ErrorLog............")
    
  }
  
  /**
   * scala中是单继承实现trait特质
   *
   * 特质的语法:trait  特质名{...}
   *
   * scala中子类实现特质分为两种情况:
   * 1.子类不需要继承父class时,extends用于实现第一个trait,后续实现其他trait使用with关键字
   * 2.子类需要继承父class时,extends用于继承trait,后续实现其他trait使用with关键字
   *
   * 特质中既可以定义抽象方法也可以定义具体方法,既可以定义抽象属性也可以定义具体属性
   *
   * @param args
   */
  def main(args: Array[String]): Unit = {
  
  
    var logger = new ErrorLogger
    
    println(logger.name)
    println(logger.age)
    logger.printMag
  
    println(logger.m1(10, 20))
 
  } 
}

四、特质叠加

由于一个类可以混入(mixin)多个trait,且trait中可以有具体的属性和方法,若混入的特质中具有相同的方法(方法名,参数列表,返回值均相同),必然会出现继承冲突问题。冲突分为以下两种:

  • 第一种,一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait之间没有任何关系,解决这类冲突问题,直接在类(Sub)中重写冲突方法。
    在这里插入图片描述
  • 第二种,一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait继承自相同的trait(TraitC),及所谓的“钻石问题”,解决这类冲突问题,Scala采用了特质叠加的策略。
    在这里插入图片描述

所谓的特质叠加,就是将混入的多个trait中的冲突方法叠加起来,案例如下,

package com.scala.charpter06

object TraitMixture {
  
  trait Logger{
    
    val name = "zhangsan"
    
    def m1(x:Int,y:Int)=x+y
  }
  
  class WarnLogger extends Logger
  
  class ErrorLogger
  
  
  /**
   * 特质混入:只让某个对象拥有特质的属性和方法
   *
   * 语法:new  类名(..)  with  特质名
   *
   * @param args
   */
  def main(args: Array[String]): Unit = {
    
    val logger = new WarnLogger
    println(logger.name)
    println(logger.m1(10, 20))
    
    val logger2 = new ErrorLogger with Logger
    println(logger2.name)
    println(logger2.m1(20, 30))
    
  }
}

五、特质叠加执行顺序

如果子类继承多个父trait之间有关系[继承同一个父trait],在子类中通过super调用同名方法的时候,方法的执行顺序是按照继承顺序从右向左开始执行,最后执行多个父trait的父trait

package com.scala.charpter06

object TraitMulit {
  
  trait Logger{
    def log(msg:String)=println("Logger..........")
  }
  
  trait Logger1  extends  Logger {
    override def log(msg:String)={
      println("Logger1..........")
      super.log("xxx")
    }
  }
  
  trait Logger2 extends  Logger {
    override def log(msg:String)= {
      println("Logger2..........")
      super.log("xxx")
    }
  }
  
  trait Logger3 extends  Logger {
    override def log(msg:String)={
      println("Logger3..........")
      super.log("xxx")
    }
    
  }
  
  
  class ErrorLogger extends Logger1  with  Logger2  with  Logger3{
  
    override def log(msg:String)= {
      println("Errorlogger..........")
      //默认调用最后一个父trait的同名方法
      super.log("xxx")
      
      //指定调用哪个父trait的方法
      super[Logger2].log("yy")
    }
    
  }
  
  
  /**
   *子类可以实现多个特质:
   *    如果这多个特质中都有同名方法,并且参数列表也一样,那么子类继承之后会出现冲突
   *
   *解决方法:子类重写同名方法
   *
   *如果子类继承多个父trait之间有关系[继承同一个父trait],在子类中通过super调用同名方法的时候,方法的执行顺序
    是按照继承顺序从右向左开始执行,最后执行多个父trait的父trait
   *
   * @param args
   */
  def main(args: Array[String]): Unit = {
  
    val logger = new ErrorLogger
  
    logger.log("hello")
  }
  
}

六、特质自身类型

1)说明

自身类型可实现依赖注入的功能。

2)案例实操

package com.scala.charpter06

import java.io.{FileInputStream, FileOutputStream, ObjectInputStream, ObjectOutputStream}

object TraitSelfType {
  
  
  class Person(val name:String, val age:Int) extends ReadAndWrite  with Serializable
  
  trait ReadAndWrite{    
    //指定必须继承的类
    _:Serializable =>
    
    //从磁盘文件读取对象
    def read() ={
      
      val ois: ObjectInputStream = new ObjectInputStream(new FileInputStream("d:/person.txt"))
      val obj: AnyRef = ois.readObject()
      ois.close()
      
      obj
    }
    
    //将对象写入磁盘
    def write()={
  
      val oos: ObjectOutputStream = new ObjectOutputStream(new FileOutputStream("d:/person.txt"))  
      oos.writeObject(this)
      oos.close()
    }
   
  }
  
  /**
   * 特质自身类型:
   * 指定子类在继承trait的时候必须先继承或者实现某一个指定的trait或者class
   *
   * 语法: this:类型=>
   *
   * @param args
   */
  def main(args: Array[String]): Unit = {
  
    val person: Person = new Person("lisi",30)
  
    person.write()
    
    val person2 = new Person("zhangsan",20)
    
    val obj = person2.read()
    
    
    val person3: Person = obj.asInstanceOf[Person]
  
    println(person3.name)
    println(person3.age)
  
  }
  
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值