本文介绍Scala中的trait特质。
1、基本知识
特质 (Traits) 用于在类 (Class)之间共享程序接口 (Interface)和字段 (Fields)。 它们类似于Java 8的接口。
即:特质里写了一些方法 和 字段,而这些是可以被所有类所共用、共享的。
这就像在类之间搭建了桥梁一样(或者打上了相同的标记),使得所有用了这个特质的类都可以有相同的特质中的方法和字段。
当然一个类可以使用多个特质,而不仅限于一个特质。
类和对象 (Objects)可以扩展特质,但是特质不能被实例化,因此特质没有参数。
特质使用关键词trait定义。
某种程度上看特质trait和类class很像,它们都不能独立运行,类必须被实例化,而特质必须被extends扩展(或继承)。
但特质比类更方便作为共享接口的地方就在于,它可以定义没有任何方法、只是约定了输入/输出参数类型的函数。
而这就可以作为类型/模式匹配的模版使用。
2、trait的定义方法
2.1 定义没有执行方法的trait
//in Scala
trait Cardetails{
def details(d:String):String
}
2.2 定义有执行方法的trait
//in scala
trait detcar{
def readdetails(d:String):String =
Source.fromString(d).mkString
}
3、trait的使用方法
3.1 类使用extends来继承没有定义任何执行方法的特质
//in scala
//定义一个特质
trait Cardetails{
def details(d:String):String
}
//定义一个类集成该特质,并在类中重写特质中的方法
class Cardet extends Cardetails {
import scala.io.Source
override def details(source:String) = {
Source.fromString(source).mkString
}
}
object car {
def main(args:Array[String]){
val c1 = new Cardet //实例化类
println(c1.details("Car details are being displayed")) //调用类中的方法
println(c1.isInstanceOf[Cardetails]) //验证下类是不是继承了这个特质
}
}
3.2 一个类即继承了一个类,同时又继承了一个特质,使用extends (类) with(特质)语法
//in scala
import scala.io.Source
//定义一个特质 detcar
trait detcar{
def readdetails(d:String):String =
Source.fromString(d).mkString +": this from trait"
}
//定义一个有参数的类Car
class Car(var cname:String, var cno:Int){
def details = cname+" "+cno
}
//定义一个有参数的类Alto,该类继承了类Car,同时拥有特质detcar。
class Alto( cname:String, cno:Int,var color:String) extends Car(cname,cno) with detcar{
//子类重写了父类的方法details,并且在重写的方法中引用了特质的方法
override def details = {
val det = readdetails(color)
cname+"\n"+cno+"\n"+"Color:"+color +"\n" +det
}
}
object Student {
def main(args:Array[String]){
val a1 = new Alto("Alto",34,"Black")
println(a1.details)
}
}
4、比较和选择使用trait 、abstract class的场景
在有可重复使用的方法、收集器的场景中,我们该怎么判断是使用trait 还是 abstract class呢?
以下4条基线可以参考:
- 如果运行效率是你关注的一个指标,那么建议使用抽象类。 因为Traits 被编译为接口,可能会有轻微的性能开销。
- 如果你需要继承一些JAVA代码,那么最好使用抽象类,因为特征没有 Java 模拟(analog),从特征继承就会很奇怪。
- 如果行为不可重用,建议使用具体类。
- 如果行为在多个不相关的类中重用,则可以使用特征。