Scala学习笔记 特质
特质是Scala代码复用的基础单元。特质将方法和字段定义封装起来,然后通过将它们混入类的方式来实现复用。但特质不同于类继承,类继承要求每个类都继承自一个明确的超类,而类可以同时混入任意数量的特质。
1.特质
关键字:trait
pl: trait Philosophical{ def philosophical() = { ....... } }
特质由一个默认的超类 -- AnyRef
特质定义好后,可以使用extends或者with关键字将他混入类中。(可以使用extends继承超类,使用with混入多个特质)
*使用extends混入特质时,隐式地继承了特质的超类。
1.从特质继承的方法和从超类继承的方法使用一致。
2.特质同时定义了一个类型。
class Frog extends Philosophical{ override def toString = "Test" } //使用特质的方法 scala> val frog = new Frog frog: Frog = Test scala> frog.philosophical() ...... //使用特质定义类 scala> val phil:Philosophical = frog phil: Philosophical = Test
总结特质与类的区别:
- 特质不能有任何“类”参数
- 类中的super调用是静态绑定的(具体实现确定),在特质中super是动态绑定的(具体实现随混入变化)。
2.Ordered特质
关于Scala中Ordered和Ordering的 比较器主要参考了https://my.oschina.net/u/2963604/blog/2251373
先附上Ordered[T] 和 Ordering[T]方法
trait Ordered[A] extends Any with java.lang.Comparable[A] { /** Result of comparing `this` with operand `that`. * * Implement this method to determine how instances of A will be sorted. * * Returns `x` where: * * - `x < 0` when `this < that` * * - `x == 0` when `this == that` * * - `x > 0` when `this > that` * */ def compare(that: A): Int /** Returns true if `this` is less than `that` */ def < (that: A): Boolean = (this compare that) < 0 /** Returns true if `this` is greater than `that`. */ def > (that: A): Boolean = (this compare that) > 0 /** Returns true if `this` is less than or equal to `that`. */ def <= (that: A): Boolean = (this compare that) <= 0 /** Returns true if `this` is greater than or equal to `that`. */ def >= (that: A): Boolean = (this compare that) >= 0 /** Result of comparing `this` with operand `that`. */ def compareTo(that: A): Int = compare(that) } object Ordered { /** Lens from `Ordering[T]` to `Ordered[T]` */ implicit def orderingToOrdered[T](x: T)(implicit ord: Ordering[T]): Ordered[T] = new Ordered[T] { def compare(that: T): Int = ord.compare(x, that) } } trait Ordering[T] extends Comparator[T] with PartialOrdering[T] with Serializable { 。。。。。 def compare(x: T, y: T): Int 。。。。 }
Ordered混入Comparable接口的方法,Comparable是一个内部比较器。定义了相同类型间的比较方式,比较方式单一,使用时需要重构compare函数。
Ordered有一个伴生对象,这个伴生对象中有一个隐式操作,implicit def orderingToOrdered[T](x: T)(implicit ord: Ordering[T]): Ordered[T]将 Ordering转化为ordered。
Ordering混入Comparator接口的方法,提供一个外部比较器,用于比较两个对象。通过比较器模板,可以自定义多种比较方式。
3.可叠加修改的特质
1.特质可以通过声明超类,意味着这个特质只有被混入童颜不过继承超类的类。
2.通过对方法添加abstract override标记 ,对抽象超类方法进行重写。关于abstract override查阅了相关资料,引用最多的还是Scala编程中的解释。即abstract override只允许使用在特质成员上,不允许使用在类成员上。它的涵义是该特质必须混入某个拥有该方法具体定义的类中。
4.特质线性化
关于线性化的内容,主要参考于https://www.cnblogs.com/yuanninesuns/p/7821964.html
首先看两个例子,来解释混入顺序的重要性
import scala.collection.mutable.ArrayBuffer abstract class IntQueue{ def get():Int def put(x:Int) } class BasicIntQueue extends IntQueue{ private val buf = new ArrayBuffer[Int] def get() = buf.remove(0) def put(x:Int) = {buf += x} } trait Doubling extends IntQueue{ abstract override def put(x:Int) = {super.put(2.x)} } trait Incrementing extends InQueue{ abstract override def put(x:Int) ={ super.put(x+1) } } trait Filtering extends InQueue{ abstract override def put(x:Int) ={ if(x >= 0) super.put(x) } } //越靠近右侧的特质越先起作用 scala> val queue = (new BasicIntQueue with Incrementing with Filtering) queue: BasicIntQueue with Incrementing with Filtering... scala> queue.put(-1);queue.put(0);queue.put(1) scala> queue.get() res16:Int = 1 scala> queue.get() res17:Int = 2
由上可以总结特质构造器的调用顺序:
1.调用超类的构造器
2.特质构造器位于超类构造器之后,类构造器之前执行
3.特质由左到右被构造
4.每个特质当中,父特质先被构造
5.如果多个特质共有一个父特质,父特质不会被重复构造
6.所有特质被构造完毕,子类被构造
我们之前提到了特质内的动态绑定,通过线性化,我们可以明确整个结构的调用链,明确动态绑定的位置。
class Animal trait Furry extends Animal trait HasLegs extends Animal trait FourLegged extends HasLegs class Cat extends Animal with Furry with FourLegged
类的线性化计算是由后向前的
最后一条线: Animal(超类优先) -> AnyRef -> Any
倒数第二条: Furry (特质调用顺序由左向右,生效由右向左) -> Animal -> AnyRef -> Any
继而:FourLegged -> HasLegs -> Furry -> Animal -> AnyRef -> Any
最后,Cat是最后一个调用,是线性化的第一个类:
Cat -> FourLegged -> HasLegs -> Furry -> Animal -> AnyRef -> Any
进一步可以看下面这个例子:
class A{ println("目前顺序:A") def Ta(s:String) = println(s"A($s)") } trait B extends A{ println("目前顺序:B") override def Ta(s:String) = println(s"B($s)") } trait C extends A{ println("目前顺序:C") override def Ta(s:String) = println(s"C($s)") } trait D extends A{ println("目前顺序:D") override def Ta(s:String) = println(s"D($s)") } trait E extends C{ println("目前顺序:E") override def Ta(s:String) = println(s"E($s)") } trait F extends C{ println("目前顺序:F") override def Ta(s:String) = println(s"F($s)") } class G extends D with E with F with B{ println("目前顺序:G") override def Ta(s:String) = println(s"G($s)") } object Test { def main(args: Array[String]): Unit = { val x = new G x.Ta("") } }
执行结果:
G extends D with E with F with B D extends A E extends C, C extends A F extends C, C extends A B extends A 按照之前的分析: 1. D -> A 2. E -> C -> D -> A 3. F -> E -> C -> D -> A 4. B -> F -> E -> C -> D -> A 5. G -> B -> F -> E -> C -> D -> A
简单总结一下:
线性化,可以了解动态绑定机制
靠右侧的特质先起作用!