10_Scala_OOP下_接口_特质

举报
alexsully 发表于 2021/05/07 00:02:44 2021/05/07
【摘要】 1 特质trait 来代替接口的概念 trait = interface + abstract class 2 构建对象时混入特质-丰富功能 3 对象的混入多个特质 - 叠加特质,特质声明 从左到右,方法执行顺序 从右到左  4 富接口 (抽象方法,又有非抽象方法) 5 特质对象-构造顺序 6 自身类型 限制混入该特质的类的类型

Java接口
interface 接口名 ; class 类名 implements 接口名1,接口2

在Java中  一个类可以实现多个接口。 接口之间支持多继承 接口中属性都是常量 接口中的方法都是抽象


Scala接口 特质trait 来代替接口的概念 trait = interface + abstract class

一个类具有某种特质,用extends关键字,如多个特质或存在父类,用with关键字连接

无父类: class 类名 extends trait1 with  trait2   
有父类: class 类名 extends 父类   with  trait1 with trait2  

特质是对继承的一种补充 Scala引入trait特征 
1 替代Java的接口,  
2 对单继承机制的一种补充(Scala是单继承)

特质trait 
1 java接口都可以当做Scala特质使用
2 特质可以同时有:抽象方法和具体方法(富接口),一个类可以实现/继承多个特质
3 特质中没有实现的方法就是抽象方法 类通过extends继承特质,通过with可以继承多个特质
4 特质中的方法并不一定是抽象的,也可以有非抽象方法(即:实现了的方法)

object Trait_introduction {
  def main(args: Array[String]): Unit = {
    val a_mysql = new A_mysql
    val b_mysql = new B_mysql

    a_mysql.getConnect //  A_mysql_connection
    a_mysql.hiTrait()  //hello Trait

    b_mysql.getConnect  //B_mysql_connection
    b_mysql.hiTrait() // hello Trait

  }}
// type Serializable = java.io.Serializable Java的接口都可以当做trait来使用
//1 java接口都可以当做Scala特质使用
object T1 extends Serializable { }

//2 特质可以同时有:抽象方法和具体方法 (富接口),一个类可以实现/继承多个特质
trait T_sql_connt { //特质
  def hiTrait(): Unit ={println("hello Trait")}
  def getConnect
}
abstract class AA {  //父类
  def get_AA
}

//3 特质中没有实现的方法就是抽象方法 类通过extends继承特质,通过with可以继承多个特质
//无父类 class  类名   extends   trait1   with    trait2
class A_mysql extends  T_sql_connt{
  override def getConnect: Unit = println("A_mysql_connection")
}

//有父类  class  类名   extends   父类   with  trait1   with   trait2
class B_mysql extends AA with  T_sql_connt{
  override def get_AA: Unit = println("get_AA_from B_mysql")
  override def getConnect: Unit = println("B_mysql_connection")
}

特质的对象 - 动态混入 MixIn (OCP闭合原则,修改源码关闭,功能扩展开放)

1 继承特质以外,也构建对象时混入特质,扩展目标类的功能 (2 可以理解为:抽象类功能进行扩展)
3 不修改类声明/定义的情况下,扩展类的功能,灵活,解耦 。
4 不影响原有的继承关系的基础上,给指定的类扩展功能

object MixInTest1 {
  def main(args: Array[String]): Unit = {
    //不影响原有的继承关系的基础上,给指定的类扩展功能
    //不修改类声明/定义的情况下,扩展类的功能,灵活,解耦
   //构建对象时混入特质 with 特质
    val a = new Mysql_A with Insert
    a.insert(97)

    val b0 = new Mysql_B {} // 抽象类实例化 {} 保留,理解为{}已经实现了抽象化(刚好mysql_B 没有方法需要实现)
    val b = new Mysql_B with Insert   // abstract class Mysql_B
    b.insert(98)

    // 抽象类有抽象方法,动态混入特质, 先with 特质,再去实现override
    val c = new Mysql_C with Insert {
      override def hello: Unit = println("hello")
    }
    c.insert(99)
  }}

// 特质
trait Insert{
  def insert(id: Int): Unit = { //已经实现
    println("insert : " + id)
  }}

class Mysql_A{ }

abstract class Mysql_B

abstract  class Mysql_C{
  def hello
}

特质的对象 -叠加特质

对象的混入多个特质 - 叠加特质,特质声明 从左到右方法执行顺序 从右到左 
Scala执行叠加对象的方法时,会首先从后面的特质(从右向左)开始执行 (如无super,直接是最右边的那个)
Scala中特质中如调用super,并不一定表示调用父特质的方法,而是向前面(左边)继续查找特质,如找不到,才会去父特质查找
指定:super[特质].xxx(…).其中的泛型必须是该特质的直接超类类型

object AddTraits2 {
  def main(args: Array[String]): Unit = {
    // 构建 从左到右
    val msql_A_B = new Msql_Test with Op_Son_A with Op_Son_B
    println(msql_A_B)  //Grandfather Father Op_Son_A  Op_Son_B


    //方法 从右到左
    // 调用对象方法时候,如无super,最右边既是 trait的实现方法,既是该对象的方法
    val msql_A_C = new Msql_Test with Op_Son_A with Op_Son_C  // "短路"
    msql_A_C.op_update(300)


    // 方法 从右到左
    // 调用对象方法时候,super, 不一定是父类,优先左边
    // Op_Son_A 的 super 调用 Op_Son_B , Op_son_B的super[Op_Father] 调用   Op_Father
    val msql_C_B_A = new Msql_Test with Op_Son_C with Op_Son_B with Op_Son_A
    msql_C_B_A.op_update(200) // Op_Son_A_update: 200 p_Son_B_update: 200  Op_father_update: 200

    // 短路review  //new Msql_Test with Op_Son_A with Op_Son_B
    //  Op_Son_B 自身的实现方法后, Op_son_B的super[Op_Father] 调用 Op_Father 而不会走到 Op_Son_A (如果是 super.op_update(id))
    msql_A_B.op_update(100)   //Op_Son_B_update: 100 Op_father_update: 100
    println("##########")

    //  Op_Son_A 自身的实现方法后, Op_son_A的super.op_update(id) 调用 左边的 Op_Son_C
    val msql_C_A = new Msql_Test with Op_Son_C with Op_Son_A
    msql_C_A.op_update(500)  //Op_Son_A_update: 500  Op_Son_C_update: 500

  }}

trait Op_GrandFather {
  println("Grandfather")
  def op_update(id: Int)
}

trait Op_Father extends Op_GrandFather {
  println("Father")
  override def op_update(id: Int): Unit = {
    println(" Op_father_update: " + id)}
}

trait  Op_Son_A extends Op_Father {
  println("Op_Son_A")
  override def op_update(id: Int): Unit = {
    println("Op_Son_A_update: " + id)
    super.op_update(id)
  }}
trait  Op_Son_B extends Op_Father {
  println("Op_Son_B")
  override def op_update(id: Int): Unit = {
    println("Op_Son_B_update: " + id)
    super[Op_Father].op_update(id) //说明:super[?] ?的类型,必须是当前的特质的直接父特质(超类)
  }}

trait  Op_Son_C extends Op_Father {
  println("Op_Son_C")
  override def op_update(id: Int): Unit = {
    println("Op_Son_C_update: " + id)
  }}


class Msql_Test{}

特质的对象 重写抽象方法
abstract override该方法仍然是一个抽象方法(因为没有完全的实现,需要其它特质继续实现[通过混入顺序])

特质的对象 富接口使用的特质 (抽象方法,又有非抽象方法)
特质的对象 具体字段
    初始化了 - 具体字段
    未初始化 - 抽象字段。具体对象混入该特质的类就具有了该字段,非继承, 变成自己的字段 直接加入类
    未被初始化的字段在具体的子类中必须被重写

object AddTrait_Abstract {
  //没有方法的具体实现,编译不通过,可重写抽象方法,这样 就必须考虑动态混入的顺序问题
  //某个方法增加了abstract override该方法仍然是一个抽象方法(因为没有完全的实现,需要其它特质继续实现[通过混入顺序])
  def main(args: Array[String]): Unit = {
    // TraitAbsAlex  的super.sayHello 找左边 TraitAbsBoB  # 非父类
    val alex = new Alex with TraitAbsBoB with TraitAbsAlex
    //sayHello Alex
    // sayHello BoB
    alex.sayHello

    // val alex1 = new Alex with TraitAbsAlex with TraitAbsBoB  // 编译不过

   // 6 特质的对象 具体字段
    // 初始化了 - 具体字段
    // 未初始化 - 抽象字段。具体对象混入该特质的类就具有了该字段,非继承, 变成自己的字段 直接加入类
    //未被初始化的字段在具体的子类中必须被重写
    val alex1 = new Alex with Trait_attr {
      override var name: String = "alex_init" //未被初始化的字段在具体的子类中必须被重写
      override def showInfo: Unit = println("this is alex")
    }}}


trait Trait_Abs {
  def sayHello
}

// abstract override该方法仍然是一个抽象方法  需要其它特质继续实现[通过 叠加特质 -> 方法混入顺序]
trait TraitAbsAlex extends Trait_Abs {
  abstract override def sayHello: Unit = {
    println("sayHello Alex")
    super.sayHello
  }}

trait TraitAbsBoB extends Trait_Abs {
  override def sayHello: Unit = {
    println("sayHello  BoB")
  }}

class Alex {}

//5 特质的对象 富接口使用的特质 (抽象/非抽象方法共存)
// 初始化了 - 具体字段
// 未初始化 - 抽象字段。具体对象混入该特质的类就具有了该字段,非继承, 变成自己的字段 直接加入类
trait Trait_attr {
  def hello: Unit = println("hello")
  var name: String
  var age: Int = 20
  def showInfo
}

特质的对象 -构造顺序

声明类同时混入特质时候 是一个整体, 如果声明类没有混入特质,而是在对象创建时候混入,构造顺序有差异

object MixinSel {
  def main(args: Array[String]): Unit = {
    //class Sumi extends Alex with Son_C with Son_D 是一个整体,在with Son_D 之前对象还未创建出来
    //Alexx          1 调用当前类的超类构造器
    //GrandFather_A  2 第一个特质的父特质构造器
    //Father_B       2 第一个特质的父特质构造器
    //Son_C          3 第一个特质构造器
    //Son_D          4 第二个特质构造器
    //Sumi           5 本类构造器
    val sumi = new Sumi

    // 动态混入 之前 Sully对象已经创建  class Sully extends Alexx & new Sully with Son_C with Son_D
    // Alexx         1 调用当前类的超类构造器
    //Sully          2 本类构造器
    //GrandFather_A  3 第一个特质的父特质构造器
    //Father_B       3 第一个特质的父特质构造器
    //Son_C          4 第一个特质构造器
    //Son_D          4 第一个特质构造器
    val sully = new Sully with Son_C with Son_D

  }}

trait GrandFather_A {println("GrandFather_A")
}

trait Father_B extends GrandFather_A {println("Father_B")
}

trait Son_C extends Father_B {println("Son_C ")
}

trait Son_D extends Father_B {println("Son_D")
}

class Alexx {println("Alexx")
}

class Sumi  extends Alexx with Son_C with Son_D {
  println("Sumi")
}

class Sully extends Alexx {
  println("Sully")
}


特质的对象 -扩展类的特性

特质可以继承类,以用来拓展该类的一些功能
混入该特质的类,会自动成为该特质所继承的超类的子类
如果混入该特质的类,继承了一个父类(A),则要求A是特质超类的子类(避免多继承现象)

特质的对象 -自身类型(目的:解决特质的循环依赖问题)  限制混入该特质的类的类型,要求混入的类必须是超类的子类

//特质可以继承类,以用来拓展该类的一些功能

trait MapException extends  Exception{
  def map: Unit = {
    println(getMessage()) //getMessage()来自于Exception
  }
}

//混入该特质的类,会自动成为该特质所继承的超类的子类
class AlexMapException extends  MapException{
  override def getMessage: String = "已经是Exception子类,可以重写getMessage方法"
}

//如果混入该特质的类,继承了一个父类(A),则要求A是特质超类的子类(避免多继承现象)

class AlexRedcuceException extends IndexOutOfBoundsException with MapException{   // 特质超类是exception
  override def getMessage: String = "IndexOutOfBoundsException 是 Exception子类"
}

class ALEX_TEST{}
//  ALEX_TEST 不是Exception 子类
//illegal inheritance; superclass ALEX_TEST is not a subclass of the superclass Exception
class AlexRedcuceException2 extends ALEX_TEST with MapException{
  override def getMessage: String = "IndexOutOfBoundsException 是 Exception子类"
}


// Logger就是自身类型特质, 自身类型后 要求混入该特质的类也是 Exception子类
// trait Logger { this: Exception => 等价于 trait Logger extends Exception,
trait Logger {
  // 明确告诉编译器,我就是Exception,如果没有这句话,下面的getMessage不能调用
  this: Exception =>
  def log(): Unit ={
    // 既然我就是Exception, 那么就可以调用其中的方法
    println(getMessage)
  }}

//class bob extends  Logger {} //报错 要求bob 必须是exception子类
//class alice extends Exception with Logger {} // alice 可以混入logger 因为alice 是 exception子类

 补充

//当一个类继承了一个trait 那么该类的实例,就可以传递给trait引用

trait MyTrait01 {}
class A extends MyTrait01 {}
object B {
  def test(m: MyTrait01): Unit = {
    println("b ok..")
  }
}

val a01 = new A
B.test(a01)
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。