基础知识
-
Trait(特征):是一种特殊的概念,相当于 Java 的接口,实际上它比接口还功能强大,它还可以定义属性和方法的实现
- Trait的定义:定义的方式和定义类的方式相同
-
scala不支持对类进行多继承,但是支持多重继承trait,使用with关键字即可,解决类的单继承问题
-
类继承trait后,必须实现其中的抽象方法和抽象字段
-
trait也可以继承自class,此时这个class就会成为所有继承该trait的类的父类
抽象方法和抽象字段
- 在triat中可以定义抽象方法,定义的抽象方法可以直接在trait中引用
- Triat可以定义抽象field,定义的抽象字段可以在trait中直接引用,此时抽象字段有默认值
object test11 { trait Sayhello{ val name :String //抽象字段 println(name) //调用抽象字段 def sayhello(name:String)=println(s"hello,$name") //具体方法调用抽象字段 } trait MakeFriends{ def makeFrinds(str:String) //抽象方法 def log(msg: String) {} //{}表示不是抽象方法 } class Person(val name:String) extends Sayhello with MakeFriends{ //with实现多继承 def makeFrinds(str:String)=print(s"可以交个朋友吗?$str") //实现MakeFriends中的抽象方法 } def main(args: Array[String]): Unit = { val person=new Person("Wei") person.sayhello("Tom") person.makeFrinds("Tom") } }
具体方法和具体字段
- 就像普通类中的具体方法和具体字段一样
object test12{ trait Person { val age: Int = 2 def eat(food: String) = println(s"吃 $food") } class Student(val name: String) extends Person {} def main(args: Array[String]): Unit = { val person = new Student("tom") println(person.age) person.eat("橘子") } }
高级知识
实例对象继承trait
- 创建对象的时候只需要某个实例对象继承trait,而不需要类中的其他对象继承trait
- 对象动态继承的trait会覆盖对象实现类的成员(Man覆盖了Person方法)
object test21{ trait Person { def eat(food: String) {println("不喜欢吃"+food)} } trait Man extends Person { override def eat(food: String){println("喜欢吃"+food)} } class Teacher(val name: String) extends Person { def sayHello { println("你好,我是" + name) eat("水果") } } def main(args: Array[String]): Unit = { val p1 = new Teacher("wiki") p1.sayHello println("\t") val p2 = new Teacher("jack") with Man p2.sayHello } }
调用链
- 类继承traitA,traitA继承traitB,traitB继承traitC,traitC继承traitD,如果要同时调用trait[A-D]中相同的方法fun1,只要将只需要将super.fun1放入到fun1中即可,形成一个调用链条
object test22 { trait KeyWord { def logger(data: String): Unit = { println("第一次密码是:" + data) } } trait KeyWord1 extends KeyWord { override def logger(data: String): Unit = { println("第二次密码是:" + data) super.logger(data) } } trait KeyWord2 extends KeyWord1 { override def logger(data: String): Unit = { println("第三次密码是:" + data) super.logger(data) } } class KeyWord3 extends KeyWord2 { def log(data: String): Unit = { logger(data) } } def main(args: Array[String]): Unit = { val s = new KeyWord3 s.log("car360") } } /** * 输出结果: * 第三次密码是:car360 * 第二次密码是:car360 * 第一次密码是:car360 */
abstract override
- trait可以直接引用抽象方法,但是子类中不可以直接引用父类的抽象方法,需要引用必须用abstract override修饰
object test23{ trait Person { def play(str: String) def eat(str: String) { play(str) } } trait Teacher extends Person { abstract override def play(str: String) { super.play(str) } def eat(str: String) { super.eat(str) } //会报错 def say(str: String) { super.play(str) } } }
构造机制
- trait也有构造函数
- 继承了trait的类的构造机制如下:
- 父类的构造函数先执行
- 类继承的traitA如果有父traitB,父traitB的构造代码先执行(多个trait继承同一个父trait,则父trait只会构造一次)
- trait的构造代码执行,多个trait从左到右依次执行
- 子类的构造函数执行
object test24{ class Person { println("Person's constructor!") } trait Number { println("Number's constructor!") } trait First extends Number { println("First's constructor!") } trait Second extends Number { println("Second's constructor!") } class Student extends Person with First with Second { println("Student's constructor!") } def main(args: Array[String]): Unit = { val stu = new Student } } //运行结果: //Person's constructor! //Number's constructor! //First's constructor! //Second's constructor! //Student's constructor!
字段的初始化
- trait没有接收参数的构造函数
- trait中的抽象字段都有默认值
- 提前定义:在调用trait的构造函数时候重写了字段值
- lazy:不能用于抽象字段,只能用于具体字段
方法一:提前定义
object test25 { trait Person{ val num:String println(num) println(num.toInt+123) } class Student(number: String) extends Person{ val num:String=number print("the new num is "+num) } def main(args: Array[String]): Unit = { // val s= new Person("123") //会报错因为他会先执行trait的println num此时是null,这时就需要用到提前定义了 val p = new { override val num: String = "123" } with Student("456") //注意:传入的参数是123而不是456 } }
方法二:用lazy
trait Person{ lazy val num:String=null //注意lazy不能用于抽象字段,只能用与具体字段 println(num.toInt+123) } class Student (number: String) extends Person{ override lazy val num:String=number print("the new num is "+num) } object test { def main(args: Array[String]): Unit = { val p = new Student("123") } }