trait就像一个拥有部分实现的接口,它提供了一个介于单一继承和多重继承的中间地带
Trait
trait是指可以混入 或融入一个类层次结构的行为。
Trait像一个拥有部分实现的接口,trait里定义和初始化的val和val会在混入trait类的内部得到实现。定义过而未初始化的val和var则认为是抽象的,需要由混入这些trait的类实现。
package com.fanshadoop
trait Friend {
val name : String
def listen() = println("your friend " + name +" is listening")
}
/**
* 类Humen没有继承其他类,可以使用关键字extends混入trait
*/
class Human(val name : String) extends Friend
class Man(override val name : String) extends Human(name)
class Woman(override val name : String) extends Human(name)
class Anima
/**
* 使用with关键字可以混入更多的trait
*/
class Dog(val name : String) extends Anima with Friend {
override def listen() = println(name + "is listening quietly")
}
类Humen没有继承其他类,可以使用关键字extends混入trait。如果继承了其他类,使用with关键字可以混入更多的trait。
一个类被混入trait后,可以通过实例调用trait方法,或者定义trait引用,访问trait中的方法。
选择性混入
可以在创建实例是混入Trait
var cat = new Cat("ali") extends Anima with Friend
var friend : Friend = cat
以trait进行装饰
trait可以用于装饰对象,使其具备一定的能力。
package com.fanshadoop
class CheckInter {
def check() = "application details check"
}
trait CreditCheck extends CheckInter {//覆盖了check方法
override def check() = "credit check " + super.check()
}
trait EmployCheck extends CheckInter {//覆盖了check方法
override def check() = "employ check " + super.check()
}
object Check {
def main(args:Array[String]) : Unit = {
val checkstance = new CheckInter with CreditCheck with EmployCheck
println(checkstance.check())
}
}
trait从右边开始调用,然后顺着super.check(),将调用传递到左边的trait。最左的trait调用的是真正的实例check()。在scala中,trait是一个强有力的工具,可以用它混入横切关注点。
Trait方法的延迟绑定
一个trait继承了抽象类,并且使用super调用了抽象方法,scala要求此方法为abstract override,此处override表示为基类提供一个方法实现,abstract则表示此方法的终极实现由混入trait的类提供。
package com.fanshadoop
abstract class Write {
<span style="white-space:pre"> </span>def write(message: String)
}
/**
*
*/
trait UpperWrite extends Write {
abstract override def write(message: String) = {
print("UpperWrite ")
super.write(message.toUpperCase())
}
}
trait FancityCheck extends Write {
abstract override def write(message: String) = {
print("FancityCheck ")
super.write(message.replaceAll("stupid", "s---------"))
}
}
class IOWrite extends Write {
def write(message: String) = println("Iowrite="+message)
}
object Check {
def main(args:Array[String]) : Unit = {
<span style="white-space:pre"> </span> val checkstance = new IOWrite with UpperWrite with FancityCheck
<span style="white-space:pre"> </span> checkstance.write("stupid------hello")
<span style="white-space:pre"> </span> val checkstance1 = new IOWrite with FancityCheck with UpperWrite
<span style="white-space:pre"> </span> checkstance1.write("stupid------hello")
}
}
输出:
FancityCheck UpperWrite Iowrite=S---------------HELLO
UpperWrite FancityCheck Iowrite=STUPID------HELLO
隐式类型转换
把方法标记为implicit,只要在当前范围内存在(通过Import导入可见,或位于当前文件),scala会自动调用它。在Predef对象里,scala已定义了一些隐式转换,Scala会默认导入它们。这样我们写1 to 3时,会将int转换为RichInt,然后调用to方法。
package com.fanshadoop
import java.util.Date
import java.util.Calendar
/**
* 类DateHelper提供了days方法,现在需要做的是把Int转换为DateHelper
*/
class DateHelper(number:Int) {
def days(when : String):Date = {
val date = Calendar.getInstance()
when match {
case DateHelper.ago => date.add(Calendar.DAY_OF_MONTH, - number)
case DateHelper.from_now => date.add(Calendar.DAY_OF_MONTH, number)
case _ => date
}
date.getTime()
}
}
object DateHelper{
val ago = "ago"
val from_now = "from_now"
/**
* 把方法标记为implicit,只要在当前范围内存在(通过Import导入可见,或位于当前文件),scala会自动调用它
*/
implicit def convertInt2DateHelper(number:Int) = new DateHelper(number)
}