特性用于类之间的接口和属性共享。它们跟java8中的接口有些类似【注:这里官方说的很准确,类似于java8的接口,而不是java7及之前的接口。因为trait同时可以声明抽象方法,也可以实现抽象方法。相当于是java接口的default的一个推广使用。】。类和伴生对象可以继承特性,但是特性不能被实例化,因此也不会有构造参数。
定义特性
一个最简单的特性可以用一个 trait 关键字和一个标志符表示:
trait HairColor
特性在泛型和抽象方法中尤为凸显优势
trait Iterator[A] {
def hasNext: Boolean
def next(): A
}
继承特性 Iterator[A] 需要一个类型A ,并且实现hasNext和next 方法
使用特性
使用关键字 extends 来继承一个特性。然后实现特性的任何抽象成员时需要加上 override 关键字
trait Iterator[A] { def hasNext: Boolean def next(): A } class IntIterator(to: Int) extends Iterator[Int] { private var current = 0 override def hasNext: Boolean = current < to override def next(): Int = { if (hasNext) { val t = current current += 1 t } else 0 } } val iterator = new IntIterator(10) iterator.next() // returns 0 iterator.next() // returns 1
这里的 IntIterator 使用一个 形参to 作为一个上边界, 继承Iterator[Int] 意味着使用 next 方法时必须返回一个Int 类型
子类型化
当需要一个给定的特性时,可以用这个特性的子类型代替。
import scala.collection.mutable.ArrayBuffer trait Pet { val name: String } class Cat(val name: String) extends Pet class Dog(val name: String) extends Pet val dog = new Dog("Harry") val cat = new Cat("Sally") val animals = ArrayBuffer.empty[Pet] animals.append(dog) animals.append(cat) animals.foreach(pet => println(pet.name)) // Prints Harry Sally
特性 Pet 有一个抽象属性name, Cat和Dog 通过结构体具体地实现了。 在最后一行,我们调用 pet.name之前,所有子类型必须实现特性 Pet.