Scala

scala-09-接口

2020-04-05  本文已影响0人  chen_666

Scala语言中,采用trait(特质,特征)来代替接口的概念,也就是说,多个类具有相同的特征(特征)时,就可以将这个特质(特征)独立出来,采用关键字trait声明
trait 特质名 {
trait体
}
一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素,所以在使用时,也采用了extends关键字,如果有多个特质或存在父类,那么需要采用with关键字连接

  • 没有父类
    class 类名 extends 特质1 with 特质2 with 特质3 ..
  • 有父类
    class 类名 extends 父类 with 特质1 with 特质2 with 特质3
object Trait02 {
  def main(args: Array[String]): Unit = {
    //使用
    val c = new C
    val e = new E
    //调用了C类实现的Trait1的geConnenct
    c.getConnect("root","12345")
    e.getConnect("scott","12345")

  }
}

//这是一个Trait1
trait Trait1 {
  //声明方法,抽象的.
  def getConnect(user: String, pwd: String): Unit
}

class A {}

class B extends A {}

class C extends A with Trait1 {
  override def getConnect(user: String, pwd: String): Unit = {
    println("连接到mysql数据库")
  }
}

class D {}

class E extends D with Trait1 {
  def getConnect(user: String, pwd: String): Unit = {
    println("e连接oracle")
  }
}

class F extends D {}

动态混入

1)除了可以在类声明时继承特质以外,还可以在构建对象时混入特质,扩展目标类的功能【反编译看动态混入本质】
2)此种方式也可以应用于对抽象类功能进行扩展
3)动态混入是Scala特有的方式(java没有动态混入),可在不修改类声明/定义的情况下,扩展类的功能,非常的灵活,耦合性低 。
4)动态混入可以在不影响原有的继承关系的基础上,给指定的类扩展功能。[如何理解]
5)抽象类中有 抽象的方法,如何动态混入特质->可以,在创建实例时,实现抽象方法即可

object MixInDemo {
  def main(args: Array[String]): Unit = {
    //创建OracleDB 实例,同时动态混入Operate3特质
    //就可以使用特质的方法,理解解耦接入.
    val oracleDB = new OracleDB with Operate3 {
      override def insert2(): Unit = {
        println("insert2")
      }
    }

    oracleDB.insert(100)//
    oracleDB.insert2()

    new MySQL3 with Operate3 {
      override def insert2(): Unit = {

      }
    }

    //如果我们要去实例化一个abstract 类,也可以,但是需要时候用匿名子类来构建
    //语句
    val mySQL = new MySQL3 {
      override def sayHi: Unit = {
       
      }
    }
  }
}
//特质
trait Operate3 {
  def insert(id: Int): Unit = {
    println("插入数据 = " + id)
  }
  def insert2()
}
//普通类
class OracleDB {
}
 
//抽象类
abstract class MySQL3 {
  def sayHi
}

叠加特质

构建对象的同时如果混入多个特质,称之为叠加特质,那么特质声明顺序从左到右,方法执行顺序从右到左。
1)特质声明顺序从左到右。
2)Scala在执行叠加对象的方法时,会首先从后面的特质(从右向左)开始执行
3)Scala中特质中如果调用super,并不是表示调用父特质的方法,而是向前面(左边)继续查找特质,如果找不到,才会去父特质查找
如果想要调用具体特质的方法,可以指定:super[特质].xxx(…).其中的泛型必须是该特质的直接超类类


//看看混入多个特质的特点(叠加特质)
object AddTraits {
  def main(args: Array[String]): Unit = {

    //说明
    //1. 创建 MySQL4实例时,动态的混入 DB4 和 File4

    //研究第一个问题,当我们创建一个动态混入对象时,其顺序是怎样的
    //总结一句话
    //Scala在叠加特质的时候,会首先从后面的特质开始执行(即从左到右)
    //1.Operate4...
    //2.Data4
    //3.DB4
    //4.File4
    val mysql = new MySQL4 with DB4 with File4
    println(mysql)

    //研究第2个问题,当我们执行一个动态混入对象的方法,其执行顺序是怎样的
    //顺序是,(1)从右到左开始执行 , (2)当执行到super时,是指的左边的特质 (3) 如果左边没有特质了,则super就是父特质
    //1. 向文件"
    //2. 向数据库
    //3. 插入数据 100
    mysql.insert(100)

    println("===================================================")
    //练习题
    val mySQL4 = new MySQL4 with  File4 with DB4
    mySQL4.insert(999)
    //构建顺序
    //1.Operate4...
    //2.Data4
    //3.File4
    //4.DB4

    //执行顺序
    //1. 向数据库
    //2. 向文件
    //3. 插入数据 = 999
  }
}

trait Operate4 { //特点
  println("Operate4...")

  def insert(id: Int) //抽象方法
}

trait Data4 extends Operate4 { //特质,继承了Operate4
  println("Data4")

  override def insert(id: Int): Unit = { //实现/重写 Operate4 的insert
    println("插入数据 = " + id)
  }
}

trait DB4 extends Data4 { //特质,继承 Data4
  println("DB4")

  override def insert(id: Int): Unit = { // 重写 Data4 的insert
    println("向数据库")
    super.insert(id)
  }
}

trait File4 extends Data4 { //特质,继承 Data4
  println("File4")

  override def insert(id: Int): Unit = { // 重写 Data4 的insert
    println("向文件")
    //super.insert(id) //调用了insert方法(难点),这里super在动态混入时,不一定是父类
    //如果我们希望直接调用Data4的insert方法,可以指定,如下
    //说明:super[?] ?的类型,必须是当前的特质的直接父特质(超类)
    super[Data4].insert(id)
  }
}
class MySQL4  {} //普通类


声明式混入和动态混入的区别是:

声明式混入,是先执行父类的构造器,以及特质的构造器,最后才是自己的构造器
动态混入,是先执行父类的构造器,然后自己的构造器,然后特质的构造器

object MixInSeq {
  def main(args: Array[String]): Unit = {

    //这时FF是这样 形式 class FF extends EE with CC with DD
    /*
    调用当前类的超类构造器
    第一个特质的父特质构造器
    第一个特质构造器
    第二个特质构造器的父特质构造器, 如果已经执行过,�就不再执行
    第二个特质构造器
     .......重复4,5的步骤(如果有第3个,第4个特质)
     当前类构造器   [案例演示]

     */
    //1. E...
    //2. A...
    //3. B....
    //4. C....
    //5. D....
    //6. F....
    val ff1 = new FF()

    println(ff1)

    //这时我们是动态混入
    /*
    先创建 new KK 对象,然后再混入其它特质

    调用当前类的超类构造器
    当前类构造器
    第一个特质构造器的父特质构造器
    第一个特质构造器.
    第二个特质构造器的父特质构造器, 如果已经执行过,就不再执行
    第二个特质构造器
    .......重复5,6的步骤(如果有第3个,第4个特质)
    当前类构造器   [案例演示]

     */
    //1. E...
    //2. K....
    //3. A...
    //4. B
    //5. C
    //6. D
    println("=======================")
    val ff2 = new KK with CC with DD
    println(ff2)

  }
}

trait AA {
  println("A...")
}

trait BB extends AA {
  println("B....")
}

trait CC extends BB {
  println("C....")
}

trait DD extends BB {
  println("D....")
}

class EE { //普通类
  println("E...")
}

class FF extends EE with CC with DD { //先继承了EE类,然后再继承CC 和DD
  println("F....")
}

class KK extends EE { //KK直接继承了普通类EE
  println("K....")
}

拓展类的特质

object ExtendTraitDemo01 {
  def main(args: Array[String]): Unit = {
    println("haha~~")
  }
}

//说明
//1. LoggedException 继承了 Exception
//2. LoggedException 特质就可以  Exception 功能
trait LoggedException extends Exception {
  def log(): Unit = {
    println(getMessage()) // 方法来自于Exception类
  }
}

//因为 UnhappyException 继承了 LoggedException
//而 LoggedException 继承了  Exception
//UnhappyException 就成为 Exception子类
class UnhappyException extends LoggedException{
  // 已经是Exception的子类了,所以可以重写方法
  override def getMessage = "错误消息!"
}

// 如果混入该特质的类,已经继承了另一个类(A类),则要求A类是特质超类的子类,
// 否则就会出现了多继承现象,发生错误。


class UnhappyException2 extends IndexOutOfBoundsException with LoggedException{
  // 已经是Exception的子类了,所以可以重写方法
  override def getMessage = "错误消息!"
}

class CCC {}

//错误的原因是 CCC 不是 Exception子类
//class UnhappyException3 extends CCC with LoggedException{
//  // 已经是Exception的子类了,所以可以重写方法
//  override def getMessage = "错误消息!"
//}

自身类型

主要是为了解决特质的循环依赖问题,同时可以确保特质在不扩展某个类的情况下,依然可以做到限制混入该特质的类的类型

object ExtendTraitDemo01 {
  def main(args: Array[String]): Unit = {
    println("haha~~")
  }
}

//说明
//1. LoggedException 继承了 Exception
//2. LoggedException 特质就可以  Exception 功能
trait LoggedException extends Exception {
  def log(): Unit = {
    println(getMessage()) // 方法来自于Exception类
  }
}

//因为 UnhappyException 继承了 LoggedException
//而 LoggedException 继承了  Exception
//UnhappyException 就成为 Exception子类
class UnhappyException extends LoggedException{
  // 已经是Exception的子类了,所以可以重写方法
  override def getMessage = "错误消息!"
}

// 如果混入该特质的类,已经继承了另一个类(A类),则要求A类是特质超类的子类,
// 否则就会出现了多继承现象,发生错误。


class UnhappyException2 extends IndexOutOfBoundsException with LoggedException{
  // 已经是Exception的子类了,所以可以重写方法
  override def getMessage = "错误消息!"
}

class CCC {}

//错误的原因是 CCC 不是 Exception子类
//class UnhappyException3 extends CCC with LoggedException{
//  // 已经是Exception的子类了,所以可以重写方法
//  override def getMessage = "错误消息!"
//}
上一篇下一篇

猜你喜欢

热点阅读