Scala学习笔记 - 特质

1.特质

在Scala中,特质Trait与Java中的接口不同。特质可以同时具有抽象方法以及具体的方法,并且Scala类可以实现多个特质。

 

2.特质中的抽象方法和具体方法

在Scala中,特质既可以拥有抽象方法,也可以拥有实现方法。只有抽象方法或者抽象字段的特质,可以当作接口来使用。

在scala中,子类实现特质时,使用extends关键字。并且在重写抽象方法或者抽象字段时,可以省略掉overwrite关键字

//构造一个Person特质,定义sayHello的抽象方法,和一个name的抽象字段
trait Person{
  def sayHello(msg:String)
  val name:String
}

//构造一个Student类实现Person特质,重写sayHello方法和通过主构造函数实现name字段
class Student(val name:String) extends Person{
  def sayHello(msg:String){println(msg+", my name is "+name)}
}

 

特质中的实现方法,在子类中直接存在,可以直接调用(类型于继承,子类可以继承父类的方法,区别在于继承特质在编译时会将方法定义在子类中)

//定义一个具有sayHello具体方法的特质Person
trait Person{
  def sayHello(name:String){
    println("Hello, My Name Is "+name)
  }
}

//定义一个Student类
class Student{}

object xxx {
  def main(args: Array[String]): Unit = {
    //创建一个Student实例,并混入特质Person
    val s = new Student with Person
    s.sayHello("Jack")
  }
}

 

在特质的具体方法中也可以调用抽象方法,但是在子类中必须重写抽象方法。

//定义一个具有sayHello具体方法的特质Person,以及一个抽象方法getMsg
trait Person{
  def getMsg:String
  def sayHello(name:String){
    println(getMsg + name)
  }
}

//定义一个Student类
class Student{}


object xxx {
  def main(args: Array[String]): Unit = {
    //创建一个Student实例,并混入特质Person,重写getMsg抽象方法
    val s = new Student with Person{
      override def getMsg = "Hi, My Name Is "
    }
    s.sayHello("Jack")
  }
}

 

3.特质中的抽象字段和具体字段

特质中具体字段可以在子类中直接使用,而抽象字段必须在子类中重写。

//定义一个特质类Person,一个具体字段eyes,一个抽象字段name
trait Person{
  val eyes = 2
  val name:String
}

//定义一个Student类
class Student{}

object xxx {
  def main(args: Array[String]): Unit = {
    //创建一个Student实例,并混入特质Person,重写name字段
    val s = new Student with Person{
      val name = "Jack"
    }
    println(s.eyes)
    println(s.name)
  }
}

控制台输出:
2
Jack

 

另外,在具体方法中可以使用抽象字段,但是在子类中必须重写抽象字段。

//定义一个特质类Person,一个具体方法sayHeool,一个抽象字段name
trait Person{
  val name:String
  def sayHello(){println("Hello, My Name Is "+name)}

}

//定义一个Student类
class Student{}

object xxx {
  def main(args: Array[String]): Unit = {
    //创建一个Student实例,并混入特质Person,重写name字段
    val s = new Student with Person{
      val name = "Tom"
    }
    s.sayHello()
  }
}

控制台输出:
Hello, My Name Is Tom

 

4.特质调用链

如下代码,在main方法中,创建一个TraitTest对象t1,并为对象混入TraitA、TraitB两个特质。但是在TraitA、TraitB两个特质中,有一个相同的方法log(msg:String)。如果代码中没有使用到super.方法名()来实现调用链,而直接调用t1.log(...)方法是会报错的。

在Scala特质调用链中的super并不是父类的意思,而是在混入特质时,如:new TraitTest with TraitA whih TraitB 代码中 with ... with ... 的顺序。

trait TraitSuper{
  def log(msg:String){
    println("TraitSuper被调用")
    println(msg)
  }
}

trait TraitA extends TraitSuper{
  override def log(msg:String){
    println("TraitA被调用")
    super.log("TraitA: "+msg)
  }
}

trait TraitB extends TraitSuper{
  override def log(msg:String){
    println("TraitB被调用")
    super.log("TraitB: "+msg)
  }
}

class TraitTest{}

object xxx {
  def main(args: Array[String]): Unit = {
    val t1 = new TraitTest with TraitA with TraitB
    t1.log("msg...")
  }
}

控制台输出如下:

TraitB被调用
TraitA被调用
TraitSuper被调用
TraitA: TraitB: msg...

 在Trait调用链中,调用的顺序即是with ... with ... 从右往左的顺序

 

5.特质的构造顺序

特质的构造器,由字段的初始化以及其他特质体内的语句组成。如:

trait Person{
  val name:String                        //这里属于构造器
  val eyes = 2                           //这里属于构造器
  println("构造器代码执行")                //这里属于构造器
  def sayHello(){println("Hello, My Name Is "+name)}
}

 

比较复杂的情况,如下:

trait Person{
  println("Person初始化")
}

trait Boy extends Person{
  println("Boy初始化")
}

trait Man extends Person{
  println("Man初始化")
}

class 小明他爸{
  println("小明他爸初始化")
}

class Student extends 小明他爸 with Boy with Man {
  println("Student初始化")
}

当创建Student实例时,控制台输出:

小明他爸初始化
Person初始化
Boy初始化
Man初始化
Student初始化

构造顺序:

1.小明他爸    (超类)
2.Person   (第一个特质的父特质)
3.Boy    (第一个特质)
4.Man    (第二个特质)
5.Student    (类)

总结特质构造器的执行顺序:

1.首先调用超类的构造器

2.从右往左调用特质的构造器,如果该特质有父特质,则会先调用父特质的构造器

3.子类构造

注意:如果多个特质持有共同一个父特质,则该父特质只会初始化一次

 

6.特质继承类

7.实现特质的两种方式

在Scala中,混入特质的方式有两种。

1.在定义类时混入特质

trait Person{}
class Student extends Person{}      //混入Person特质

2.在创建对象时混入特质

trait Person{}

object xxx{
  def main(args: Array[String]): Unit = {
    val s = new Student with Person    //创建对象时混入Person特质
  }
}

两种方式不同处在于:

  定义类的时候混入特质时,该类所有对象都具有该特质的方法和属性。

  创建对象的时候混入特质,则只有该对象具有特质的方法和属性。

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/gudanjava/p/10172137.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值