博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Scala学习笔记 - 特质
阅读量:6223 次
发布时间:2019-06-21

本文共 3972 字,大约阅读时间需要 13 分钟。

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具体方法的特质Persontrait 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,以及一个抽象方法getMsgtrait 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,一个抽象字段nametrait 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)  }}控制台输出:2Jack

 

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

//定义一个特质类Person,一个具体方法sayHeool,一个抽象字段nametrait 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

你可能感兴趣的文章
PHP连接Mysql常用API(mysql,mysqli,pdo)区别与联系
查看>>
java中的CAS
查看>>
简单的markdown在线解析服务
查看>>
Linux基础(day44)
查看>>
Git 分支创建及使用
查看>>
MariaDB安装, Apache安装
查看>>
多线程三分钟就可以入个门了!
查看>>
从道法术三个层面理解区块链:术
查看>>
elasticsearch入门使用
查看>>
数据结构与算法4
查看>>
tomcat去掉项目名称
查看>>
微服务架构的优势与不足(一)
查看>>
分布式服务治理框架Dubbo
查看>>
小程序好的ui框架选择
查看>>
今天学习了
查看>>
Tomcat安装、配置、优化及负载均衡详解
查看>>
虹软人脸识别SDK(java+linux/window) 初试
查看>>
ppwjs之bootstrap文字排版:到标题元素
查看>>
为了解「鼠语」华盛顿大学开发DeepSqueak深度学习软件
查看>>
jQuery-ajax
查看>>