特质(trait)的定义
Scala和Java语言一样,使用很强的限制策略,避免了多继承的问题。在Java语言中,只允许继承一个超类,但可以实现多个接口,但Java接口中有其自身的局限性:接口中只能包含抽象方法,不能包含具体方法,包含的字段是常量 。Scala语言利用trait解决了该问题,在Scala的trait中,不单可以包含抽象方法还可以包含字段和具体方法。
trait Animal01 {
def eat():Unit
def exercise():String
}
trait Animal02{
def eat02():Unit
def exercise02():String
def color():Unit={
println("this dog is black")
}
}
//实现一个trait使用extends
class Dog01 extends Animal01{
override def eat(): Unit = {println("A dog loves eating meat")}
override def exercise(): String = {
"A dog loves running!"
}
}
//实现多个trait第一个使用extends,其余使用with A with B。。。
//如果有类,这类使用extends,trait使用with,一次继承只能继承一个类,和java一样
class Dog02 extends Animal01 with Animal02{
override def eat(): Unit = {println("This dog loves eating leaves")}
override def exercise(): String = {"loves running"}
override def eat02(): Unit = {println("loves eating meat")}
def exercise02(): String = {"loves crawling"}//trait未实现的方法可以不带关键字override
override def color(): Unit = {println("it becomes white")}//trait实现的方法必须带关键字override
}
object TestDemo{
def main(args: Array[String]): Unit = {
val dog01 = new Dog01()
dog01.eat()
val dog02 = new Dog02//无参构造器可以不带括号
dog02.eat//无参方法也可以不用带括号
}
}
总结:
Java中:
1,接口是一种特殊的抽象类
2,里面所有方法都是抽象方法
scala中:
1,特质里面的方法既可以实现,也可以不实现,
2,抽象类使用extends单继承
3,实现特质,如果没有继承其他类,第一个特质使用extends,后面使用with,所以实现特质有两种情况:
a. 实现一个特质使用extends
b. 实现两个及以上,第一个使用extends,后面的使用with
Trait的几种不同使用方式:
1,当做Java接口使用的trait都是抽象字段和抽象方法
2,带实现方法的trait
3,带具体字段的trait
Traits的底层实现采用Java的抽象类。
初始化顺序
object ParentConstructor {
def main(args: Array[String]): Unit = {
//执行顺序时先初始化父类,在执行本身,由于实现了A接口,所以初始化A接口,再初始化本身
val c: C = new C //执行顺序为:trait B->trait A->trait C
}
}
trait A {
println("trait A")
}
class B {
println("trait B")
}
class C extends B with A{
println("trait C")
}
object ParentConstructor {
def main(args: Array[String]): Unit = {
//特质和父类没有关系,只和当前混入的类有关系,所以在调用时,父类先执行,
// 然后当前混入的特质再执行,然后当前类再执行
//如果父类混入了相同的特质,那么特质代码只会执行一次
val c: C = new C //执行顺序为:trait A->trait B->trait C
}
}
trait A {
println("trait A")
}
class B extends A {
println("trait B")
}
class C extends B with A{
println("trait C")
}
混入
trait MixedTest {
def travelling(msg:String):Unit={}
}
trait MixedTest02 extends MixedTest{
override def travelling(msg: String): Unit = {
println("MixedTest02: "+msg)
}
}
trait MixedTest03 extends MixedTest{
override def travelling(msg: String): Unit = {
println("MixedTest03: "+msg)
}
}
class Test(val name:String) extends MixedTest02{
def hello():Unit={
println("hello "+ name)
travelling("hello is invoked")//实现MixedTest02的方法
}
}
object TestDemo02{
def main(args: Array[String]): Unit = {
val test=new Test("xh")
test.hello()//结果是 //hello xh //MixedTest02: hello is invoked
//混入方法
val test02 = new Test("小黑") with MixedTest03
test02.hello()//结果是 //hello 小黑 //MixedTest03: hello is invoked
//可以看到其调用的travelling方法是MixedTest03的,也就是说,这种方法可以改变已经
//定型的类的方法的具体实现
}
}
object ParentConstructor {
def main(args: Array[String]): Unit = {
val sql: MySql = new MySql
sql.insert()
}
}
trait Operate {
println("Operate......")
def insert(): Unit = {
println("插入数据")
}
}
trait DB extends Operate {
println("DB......")
override def insert() {
println("向数据库")
super.insert()
}
}
trait File extends Operate {
println("File......")
override def insert(): Unit = {
println("向文件")
super.insert()
}
}
//多特质混入时,代码执行顺序为从左到右,如果有父类特质,会优先执行
// 多特质混入时,方法调用的顺序为从右到左
// 特质中super关键字不是指代父特质,指代上一级特质
//如果希望super指向父特质,需要增加特殊操作:super[特质]
//Java中的接口可以当作Scala中的特质使用
class MySql extends DB with File {
}
链
trait Handler {
def handler(data:String){}
}
trait Handler_A extends Handler{
override def handler(data: String): Unit = {
println("Handler_A: "+data)
super.handler(data)
}
}
trait Handler_B extends Handler{
override def handler(data: String): Unit = {
println("Handler_B: "+data)
super.handler(data)
}
}
trait Handler_C extends Handler{
override def handler(data: String): Unit = {
println("Handler_C: "+data)
super.handler(data)
}
}
class TraitChain(val name:String) extends Handler_C with Handler_B with Handler_A{
def sayHello()={
println("hello "+ name)
handler(name)
}
}
object HandlerTest{
def main(args: Array[String]): Unit = {
val traitChain = new TraitChain("xh")
traitChain.sayHello()
/**
* 结果:
* hello xh
* Handler_A: xh
* Handler_B: xh
* Handler_C: xh
* 也就是说形成这种链表(每个trait调用父类方法很重要,即:super.handler(data))后,
* 对子类这些trait是平等的,他们的方法都会调用,只是从前后往前,
*/
}
}