美文网首页Scala
scala-09-接口

scala-09-接口

作者: chen_666 | 来源:发表于2020-04-05 20:49 被阅读0次

    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....")
    }
    

    拓展类的特质

    • 特质可以继承类,以用来拓展该特质的一些功能
    • 所有混入该特质的类,会自动成为那个特质所继承的超类的子类
    • 如果混入该特质的类,已经继承了另一个类(A 类),则要求 A 类是特质超类的子类,否则就会出现了多继承现象,发生错误
    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 = "错误消息!"
    //}
    

    相关文章

      网友评论

        本文标题:scala-09-接口

        本文链接:https://www.haomeiwen.com/subject/zmupphtx.html