Scala入门到放弃——特质trait(七)

十、特质trait

类似于Java中的接口

语法

  • 特质关键词trait

  • 特质可以同时用于抽象方法和具体方法

  • 无父类 实现特质extends trait1 with trait2 with trait3 ...

  • 有父类 实现特质extends 父类 with 特质1 with 特质2 ...

当做接口的特质

  1. Scala可以完全像Java接口一样工作, 你不需要将抽象方法声明为 abstract, 特质中未被实现的方法默认就是抽象方法;
  2. 类可以通过 extends 关键字继承特质, 如果需要的特质不止一个, 通过 with 关键字添加额外特质
  3. 重写特质的抽象方法时, 不需要 override 关键字
  4. 所有 Java 接口都可以当做 Scala 特质使用 trait Animals extends Serializable with Cloneable
package traits

// 注意: java的接口可以当做scala的trait使用
// trait Animals extends Serializable with Cloneable

// 等价于: public interface Animals {}
trait Animals {
  // 只有方法的声明,没有实现
  // 等价于 void eat();
  def eat(): Unit
}

// 如果当前类Dog没有父类  extends 特质
class Dog extends Animals {
  // 等价于 实现接口中的 public void eat()
  override def eat(): Unit = println("dog eat shit")
}

object AnimalsDemo {
  def main(args: Array[String]): Unit = {
    val dog = new Dog
    dog.eat()
  }
}

带有具体实现的特质

trait Animals {
  def eat(food: String): String
  def sleep():Unit = println("animals sleep~~~") // 特质带有方法实现的方法
}

在这里插入图片描述

注意:让特质混有具体行为有一个弊端. 当特质改变时, 所有混入该特质的类都必须重新编译

带有特质的对象 动态混入(mixin) [ 重点]

在构造单个对象时, 你可以为它添加特质

  • 特质可以将对象原本没有的方法与字段加入对象中, 功能扩展
  • 无需修改类声明定义,扩展类的功能,灵活简便
  • 如果特质和对象改写了同一超类的方法, 则排在右边的先被执行
package traits.test1.mixin

trait Animals {
  def eat(): Unit
}

trait Sheep extends Animals {
  // 实现特质声明的方法
  override def eat() = {
    println("吃草")
  }

  def run = println("在跑...")

  def sleep
}

class Person extends Animals {
  override def eat(): Unit = {
    println("吃食物")
  }
}

object Person {
  def main(args: Array[String]): Unit = {
    val person = new Person with Sheep {
      override def sleep: Unit = println("睡觉觉!!!")
    } // 动态混入
    person.eat // Person 和 Sheep都有eat方法,调用时从右往左调用  输出 吃草
    person.run // Person 中没有run方法,Sheep特质将自己的方法混入Person
    person.sleep  // 睡觉觉!!!
  }
}

在这里插入图片描述

this别名

看scala的源码的话很发现很多源码开头都有一句:self => 这句相当于给this起了一个别名为selfself不是关键字,可以用除了this外的任何名字命名(除关键字)。就下面的代码,在Student内部,可以用this指代当前对象,也可以用self指代,两者是等价的。

class Student {
  self => // this起别名
  val x = 2

  def foo = self.x + this.x
}

object Student {
  def main(args: Array[String]): Unit = {
    val s1 = new Student
    println(s1.foo) //4
  }
}

它的一个场景是用在有内部类的情况下:

class Outer {
  outer =>
  val v1 = "here"
  class Inner {
    inner =>
    val v1 = "-------------"
    println(outer.v1) // 用outer表示外部类,相当于Outer.this
    println(inner.v1)
  }
}

self-type

强制混入

自类型用于声明一个特质必须混入其他特质,尽管该特质没有直接扩展其他特质。 这使得所依赖的成员可以在没有导入的情况下使用。

自类型是一种细化 thisthis 别名之类型的方法。 语法看起来像普通函数语法,但是意义完全不一样。

要在特质中使用自类型,写一个标识符,跟上要混入的另一个特质,以及 =>(例如 someIdentifier: SomeOtherTrait =>

package traits

trait A {
  val name: String
}

trait B {
  this: A => // this:混入类型 => [self type] 在特质中混入特质,所依赖的成员可以再没有导入的情况下使用
  def sayHi = s"Hello:$name"
}

class C(val name: String) extends B with A {

}

object C {
  def main(args: Array[String]): Unit = {
    val c = new C("zs")
    println(c.sayHi)
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章