标签:
多重继承产生菱形继承问题。解决多重继承可能导致的问题消耗的资源远比多重继承产生的价值高。
Java8中新增一个特性:default method ,可以在interface中实现的方法。Scala特质类似Java 8的interface。
Scala类只能继承一个父类,但可以由多个特质拓展而成。Scala不支持多重继承,取而代之的是特质。Trait可以作为工具方法混入到相关类中。
Scala使用特质达到类似多重继承的效果。一个类可以扩展自一个或多个特质,一个特质可以被多个类扩展。特质能限制被什么样的类所扩展。
所有Java interface都能当做是特质使用在Scala中。
trait Logger { def log(msg:String) }
scala中没有 implements ,所以使用 extends 即可。
class ConsoleLogger extends Logger{ def log(msg:String){ println(msg) } }
重写特质的方法,不需要override关键字。
若需要的特质不止一个,可以使用with关键字来添加额外的特质:
class ConsoleLogger extends Logger with Cloneable with Serializable { // ... }
说明:Logger with Cloneable with Serializable 应该被看成一个整体。
trait Logger{ def log(msg:String){ println(msg) } }
使用特质
class SavingAccount extends Account with ConsoleLogger { def withdraw(amount:Double){ if(amount > balance) log("Insufficient funds") else balance -= amount } // ... }
在Scala中,一般说,Logger的功能被“混入”了SavingAccount类。
trait Logger { def log(msg:String) }
重写特质需要使用override 。
trait TimestampLogger extends Logger { override def log(msg:String){ super.log(new java.util.Date()+” ”+msg) } }
特质是Scala里代码复用的基础单元,封装了方法和字段的定义。
特质的定义使用保留字trait,具体语法与类定义相似,除了不能拥有构造参数。
trait reset{ def reset(m:Int, n:Int) = if(m >= n) 1 }
一旦特质被定义了,就可以混入(mixin)到类中。
class week extends reset { ... }
当要混入多个特质时,利用with关键字:
class week extends reset with B with C {...}
特质的成员可以是抽象的,而且,不需要使用abstract声明。
同样的,重写特质的抽象方法无需给出override。
但是,多个特质重写同一个特质的抽象方法需给出override。
除了在类定义中混入特质以外,还可以在特质定义中混入特质:
trait reseting extends reset{...}
在对象构造时混入特质:
val five = new month with reseting
特质的构造是有顺序的:从左到右被构造。
构造器按如下顺序构造:
超类
父特质
第一个特质
第二个特质(父特质不重复构造)
类
如果class A extends B1 with B2 with B3....
那么,串接B1、B2、B3...等特质,去掉重复项且右侧胜出。
特质的一个主要应用方面在于接口,根据类已有的方法自动为类添加方法。
利用特质实现富接口:
构造一个具有少量抽象方法和大量基于抽象方法的具体方法的特质。
那么,只要把特质混入类中,通过类重写抽象方法后,类便自动获得大量具体方法。
trait Logger{
def log(msg:String)
def warn(msg:String) { log(“server”+msg) }
def server(msg:String) { log(“server”+msg) }
}
class week extends Logger{
def log(msg:String){println(msg)}
server(“HI”)
}
特质的另一个应用方面在于:为类提供可堆叠的改变(super保留字)
当为类添加多个互相调用的特质时,从最后一个开始进行处理。
在类中super.foo() 这样的方法调用是静态绑定的,明确是调用它的父类的 foo() 方法。
在特质中写下了 super.foo() 时,它的调用是动态绑定的。调用的实现讲在每一次特质被混入到具体类的时候才被决定。
因此,特质混入的次序的不同其执行效果也就不同。
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 Incrementing extends IntQueue {
abstract override def put(x: Int) {
super.put(x + 1)
}
}
trait Doubling extends IntQueue {
abstract override def put(x: Int) {
super.put(2 * x)
}
}
object TestClient extends App {
val queue1 = (new BasicIntQueue with Incrementing with Doubling)
//Doubling.put(2*2)->Incrementing.put(4+1)
queue1.put(2)
println(queue1.get()) //result is 5
val queue2 = (new BasicIntQueue with Doubling with Incrementing)
//Incrementing.put(2+1)->Doubling.put(2*3)
queue2.put(2)
println(queue2.get()) //result is 6
}
App特质只支持单线程。而普通的main可以支持多线程。
扩展类和特质
构造一个扩展了指定类和特质的类的对象,同时拥有对象定义中给出的所有特性
标签:
原文地址:http://www.cnblogs.com/shijiaqi1066/p/4623659.html