首页 > 技术文章 > scala trait 构建类对象 构建匿名子类

sowhat1412 2019-10-29 14:08 原文

在scala中 trait 可以认为是 Java中interface 跟abstract class 集中的混合体,JVM 8 中 特质可以包含具体方法跟抽象方法,自己理解下 如果一个特质中既有抽象方法又有具体方法时,别的类继承该特质时的背后流程。scala 中 可以允许特质的动态混入,

   构建对象的同时如果混入多个特质,称之为叠加特质

object aiguigu {
  def main(args: Array[String]): Unit = {
    val t  = new T with T3
    t.myprint
    println("="*15)
    val t2 = new T with T4
    t2 myprint
  }
}

trait T1{
  println("T1 is created")
  def myprint = println("T1 is my print")
}
trait T2{
  println("T2 is created")
  def myprint = println("T2 is my print")
}

trait T3 extends T1 with T2 {
  println("T3 is created")

  override def myprint: Unit = super.myprint
}

trait T4 extends T2 with T1 {
  println("T3 is created")

  override def myprint: Unit = super.myprint
}

class T {}

 结果如下:

T1 is created
T2 is created
T3 is created
T2 is my print
===============
T2 is created
T1 is created
T3 is created
T1 is my print

 

object aiguigu {
  def main(args: Array[String]): Unit = {
    val mysql = new MySQL4 with DB4 with File4
    mysql.insert(100)
  }
}

trait Operate4 {
  println("Operate4")
  def insert(id: Int)
}

trait Data4 extends Operate4 {
  println("Data4")
  def insert(id: Int): Unit = {
    println("插入数据 = " + id)
  }
}

trait DB4 extends Data4 {
  println("DB4")
  override def insert(id: Int): Unit = {
    println("向数据库")
    super.insert(id)
  }
}

trait File4 extends Data4 {
  println("File4")
  override def insert(id: Int): Unit = {
    println("向文件")
    super.insert(id)
    // super[Data4].insert(id)
  }
}

class MySQL4{}

结果如下: 

Operate4
Data4
DB4
File4
向文件
向数据库
插入数据 = 100

结果:

  1. trait 特质实例化的执行顺序是:从左到右   
  2. trait 调用多个同名方法时执行顺序是:从右到左 , 如果特质中调用了super,并不是表示调用父特质的方法,而是向前(向左) 继续查找特质,如果找不到才会去父特质查找。
  3. 如果想要调用具体特质的方法 可以指定super[特质].xxx(...) 其中的泛型必须是该特质的直接超类类型。 比如 super[Data4].insert(id) 执行顺序如下
    Operate4
    Data4
    DB4
    File4
    向文件
    插入数据 = 100

object tiger {
  def main(args: Array[String]): Unit = {
    /*
    构建类对象, 在混入特质时,该对象还没有创建
    调用当前类的超类构造器
    第一个特质的父特质构造器
    第一个特质构造器
    第二个特质构造器的父特质构造器, 如果已经执行过, 就不再执行
    第二个特质构造器
    .......重复 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....")
}

 分析两种方式对构造顺序的影响
第 1 种方式实际是构建类对象, 在混入特质时,该对象还没有创建。
第 2 种方式实际是构造匿名子类,可以理解成在混入特质时,对象已经创建了然后添加特质属性。

 

推荐阅读