scala中提供了“trait(特质)”这个特殊概念,特质并非接口,它可以同时拥有抽象方法和具体方法,一个类可以拥有多个特质,这一特性解决了java接口的问题。
类可以通过“extends”关键字继承trait,这里不是implement,二是extends,类继承了trait后必须实现trait中的抽象方法,实现时不需要使用“override”关键字。scala中不支持类的多继承,但支持trait多继承,使用“with”关键字链接多个trait。
trait不仅可以定义抽象方法,还可以定义具体实现的方法。
特质还可以这样使用在创建对象时使用“with”关键字为其增加trait,并实现相应的抽象方法
trait中可以定义具体或抽象的字段,当一个类继承了这个trait,表明这个类拥有了trait中的字段,不需要使用“super”;而继承一个类,表明可以调用父类中的子弹,但不拥有字段,使用“super”关键字。
多个特质的构造顺序,有一个例子说明一下:
trait Logged {
println("Logged构造器")
def log(msg : String){
println(msg)
}
}
trait TimeLog extends Logged{
println("TimeLog构造器")
override def log(msg : String){
println("this is TimeLog : " + msg)
super.log(new java.util.Date() + ",msg")
}
}
trait SplitLog extends Logged{
println("SplitLog构造器")
val splitNum = 15
override def log(msg : String){
println("this is SplitLog : " + msg)
super.log(if(msg.length() > splitNum) msg.substring(0, splitNum) else msg)
}
}
class Student extends TimeLog with SplitLog{
def sayHello {
log("liumingxin,liumingxin,liumingxin")
println("hello")
}
}
object StudentApp extends App{
val s = new Student
s.sayHello
}
//----------------------------
//运行结果
Logged构造器
TimeLog构造器
SplitLog构造器
this is SplitLog : liumingxin,liumingxin,liumingxin
this is TimeLog : liumingxin,lium
Thu Aug 16 10:39:09 CST 2018,msg
hello
继承多个trait的时候,总体原则是“从左到右,从父到子构造;从右到左,从子到父调用”。
自身类型(selftype)
有很多特质不是所有类都能随随便便继承的,例如异常类所能继承的特质,其他类继承并不合适,所以需要对特质加以约束。
通过“this : T => {}”的形式,指定这个特质只能被T或T的子类继承
trait ExceptionLog extends Logged{
//
//this : Exception => {}以外的区域不能写代码,否则会报错
//
this : Exception => {
println("Logged构造器")
def log(msg : String){
println(msg)
}
}
}
也可以通过“this : {} => {}”的形式,指定这个特质能被继承的规则,“this : {}”中的“{}”就可以设置规则,比如必须拥有指定对象、方法的类才能继承这个特质。
必须拥有“def getLog() : String”这个方法的类才能继承此trait
trait ExceptionLog extends Logged{
this : {def getLog() : String} => {
def log(msg : String){
println(msg)
}
}
}
必须拥有“val log : String”这个常量的类才能继承此trait
trait ExceptionLog extends Logged{
this : {val log : String} => {
def log(msg : String){
println(msg)
}
}
}
必须同时拥有“val log : String”和“def getLog() : String”的类才能继承此trait
trait ExceptionLog extends Logged{
this : {
val log : String
def getLog() : String} => {
def log(msg : String){
println(msg)
}
}
}
需要注意的是,只能定义一次自身类型,不能定义多个this