zoukankan      html  css  js  c++  java
  • Scala 关于叠加特性的理解

    代码示例

    package com.atguigu.chapter08.mixin
    
    //看看混入多个特质的特点(叠加特质)
    object AddTraits {
      def main(args: Array[String]): Unit = {
    
        val mysql = new MySQL4 with DB4 with File4
        println(mysql)
        mysql.insert(100)
    
        println("===================================================")
      
      }
    }
    
    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  {} //普通类

    关系图

    问题

    在构建对象时,它的构建顺序是

    Scala在叠加特质的时候,会从左到右依次构建:

        构建完MySQL4之后开始构建DB4==》DB4的父特质是Data4,所以会先构建Data4 ==》Data4 的父特质是Operate4,所以先构建Operate4 ==》所有父类构建完成之后,DB4开始完成自己的构造==》

        开始构造FIle4时,依然还是会先找父类构造,但因为父类之前已经被构造过,所以就跳过,直接构造自己

    所以输出为
    1.Operate4...    
    2.Data4
    3.DB4
    4.File4

    当我们执行一个动态混入对象的方法,其执行顺序是怎样的

    顺序是,(1)从右到左开始执行 , (2)当执行到super时,是指的左边的特质 (3) 如果左边没有特质了,则super就是父特质

    所以输出为:

    1. 向文件"
    2. 向数据库
    3. 插入数据 100

    以为这就完了吗?

    补充

    动态混入  和    常规混入 在构建时的一个细微差别:

      动态混入会先把对象创建好在构建特质,而常规混入是先 构建父类,然后再构建特质,最后再是构建对象

    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....")
    }
  • 相关阅读:
    day12 bash中的if、for
    day11 grep正则匹配
    day10 nfs服务,nginx负载均衡,定时任务
    SpringMVC11文件上传
    SpringMVC10数据验证
    SpringMVC09异常处理和类型转化器
    SpringMVC08转发和重定向
    SpringMVC07处理器方法的返回值
    SpringMVC06以对象的方式获取前台的数据
    SpringMVC05使用注解的方式
  • 原文地址:https://www.cnblogs.com/yangxusun9/p/12775396.html
Copyright © 2011-2022 走看看