scala当中的特质trait
1、将trait作为接口使用
- Scala中的trait是一种特殊的概念;
- 首先先将trait作为接口使用,此时的trait就与Java中的接口 (interface)非常类似;
- 在trait中可以定义抽象方法,就像抽象类中的抽象方法一样,只要不给出方法的方法体即可;
- 类可以使用extends关键字继承trait,注意,这里不是 implement,而是extends ,在Scala中没有 implement 的概念,无论继承类还是trait,统一都是 extends;
- 类继承后,必须实现其中的抽象方法,实现时,不需要使用 override 关键字;
- Scala不支持对类进行多继承,但是支持多重继承 trait,使用 with 关键字即可。
举例说明:
trait HelloTrait { def sayHello(): Unit } trait MakeFriendsTrait { def makeFriends(c: Children): Unit } //多重继承 trait class Children(val name: String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable{ def sayHello() =println("Hello, " + this.name) def makeFriends(c: Children) = println("Hello, my name is " + this.name + ", your name is " + c.name) } object Children{ def main(args: Array[String]) { val c1=new Children("tom") val c2=new Children("jim") c1.sayHello()//Hello, tom c1.makeFriends(c2)//Hello, my name is tom, your name is jim } } |
2、在trait中定义具体的方法
- Scala中的trait不仅可以定义抽象方法,还可以定义具体的方法,此时 trait 更像是包含了通用方法的工具,可以认为trait还包含了类的功能。
举例说明:
/** * 比如 trait 中可以包含很多子类都通用的方法,例如打印日志或其他工具方法等等。 * spark就使用trait定义了通用的日志打印方法; */ trait Logger { def log(message: String): Unit = println(message) } class PersonForLog(val name: String) extends Logger { def makeFriends(other: PersonForLog) = { println("Hello, " + other.name + "! My name is " + this.name + ", I miss you!!") this.log("makeFriends method is invoked with parameter PersonForLog[name = " + other.name + "]") } } object PersonForLog{ def main(args: Array[String]) { val p1=new PersonForLog("jack") val p2=new PersonForLog("rose") p1.makeFriends(p2) //Hello, rose! My name is jack, I miss you!! //makeFriens method is invoked with parameter PersonForLog[name = rose] } } |
3、在trait中定义具体field
- Scala 中的 trait 可以定义具体的 field,此时继承 trait 的子类就自动获得了 trait 中定义的 field;
- 但是这种获取 field 的方式与继承 class 的是不同的。 如果是继承 class 获取的 field ,实际上还是定义在父类中的;而继承 trait获取的 field,就直接被添加到子类中了。
举例说明:
trait PersonForField { val age:Int=50 } //继承 trait 获取的field直接被添加到子类中 class StudentForField(val name: String) extends PersonForField { def sayHello = println("Hi, I'm " + this.name + ", my age is "+ age) } object StudentForField{ def main(args: Array[String]) { val s=new StudentForField("tom") s.sayHello } } |
4、在trait中定义抽象field
- Scala中的trait也能定义抽象field, 而trait中的具体方法也能基于抽象field编写;
- 继承trait的类,则必须覆盖抽象field,提供具体的值;
举例说明:
trait SayHelloTrait { val msg:String def sayHello(name: St ring) = println(msg + ", " + name) } class PersonForAbstractField(val name: String) extends SayHelloTrait { //必须覆盖抽象 field val msg = "Hello" def makeFriends(other: PersonForAbstractField) = { this.sayHello(other.name) println("I'm " + this.name + ", I want to make friends with you!!") } } object PersonForAbstractField{ def main(args: Array[String]) { val p1=new PersonForAbstractField("Tom") val p2=new PersonForAbstractField("Rose") p1.makeFriends(p2) } } |
5、在实例对象指定混入某个trait
- 可在创建类的对象时,为该对象指定混入某个trait,且只有混入了trait的对象才具有trait中的方法,而其他该类的对象则没有;
- 在创建对象时,使用 with 关键字指定混入某个 trait;
举例说明:
trait LoggedTrait { // 该方法为实现的具体方法 def log(msg: String) = {} } trait MyLogger extends LoggedTrait{ // 覆盖 log() 方法 override def log(msg: String) = println("log: " + msg) } class PersonForMixTraitMethod(val name: String) extends LoggedTrait { def sayHello = { println("Hi, I'm " + this.name) log("sayHello method is invoked!") } } object PersonForMixTraitMethod{ def main(args: Array[String]) { val tom= new PersonForMixTraitMethod("Tom").sayHello //结果为:Hi, I'm Tom // 使用 with 关键字,指定混入MyLogger trait val rose = new PersonForMixTraitMethod("Rose") with MyLogger rose.sayHello // 结果为: Hi, I'm Rose // 结果为: log: sayHello method is invoked! } } |
6、trait 调用链
- Scala中支持让类继承多个trait后,可依次调用多个trait中的同一个方法,只要让多个trait中的同一个方法,在最后都依次执行 super 关键字即可;
- 类中调用多个trait中都有的这个方法时,首先会从最右边的trait的方法开始执行,然后依次往左执行,形成一个调用链条;
- 这种特性非常强大,其实就是设计模式中责任链模式的一种具体实现;
案例说明:
trait HandlerTrait { def handle(data: String) = {println("last one")} } trait DataValidHandlerTrait extends HandlerTrait { override def handle(data: String) = { println("check data: " + data) super.handle(data) } } trait SignatureValidHandlerTrait extends HandlerTrait { override def handle(data: String) = { println("check signature: " + data) super.handle(data) } } class PersonForRespLine(val name: String) extends SignatureValidHandlerTrait with DataValidHandlerTrait { def sayHello = { println("Hello, " + this.name) this.handle(this.name) } } object PersonForRespLine{ def main(args: Array[String]) { val p=new PersonForRespLine("tom") p.sayHello //执行结果: // Hello, tom // check data: tom // check signature: tom // last one } } |
7、混合使用 trait 的具体方法和抽象方法
- 在 trait 中,可以混合使用具体方法和抽象方法;
- 可以让具体方法依赖于抽象方法,而抽象方法则可放到继承 trait的子类中去实现;
- 这种 trait 特性,其实就是设计模式中的模板设计模式的体现;
举例说明:
trait ValidTrait { //抽象方法 def getName: String //具体方法,具体方法的返回值依赖于抽象方法 def valid: Boolean = {"Tom".equals(this.getName) } } class PersonForValid(val name: String) extends ValidTrait { def getName: String = this.name } object PersonForValid{ def main(args: Array[String]): Unit = { val person = new PersonForValid("Rose") println(person.valid) } } |
8、trait的构造机制
- 在Scala中,trait也是有构造代码的,即在trait中,不包含在任何方法中的代码;
- 继承了trait的子类,其构造机制如下:
- 父类的构造函数先执行, class 类必须放在最左边;多个trait从左向右依次执行;构造trait时,先构造父 trait,如果多个trait继承同一个父trait,则父trait只会构造一次;所有trait构造完毕之后,子类的构造函数最后执行。
举例说明:
class Person_One { println("Person's constructor!") } trait Logger_One { println("Logger's constructor!") } trait MyLogger_One extends Logger_One { println("MyLogger's constructor!") } trait TimeLogger_One extends Logger_One { println("TimeLogger's contructor!") } class Student_One extends Person_One with MyLogger_One with TimeLogger_One { println("Student's constructor!") } object exe_one { def main(args: Array[String]): Unit = { val student = new Student_One //执行结果为: // Person's constructor! // Logger's constructor! // MyLogger's constructor! // TimeLogger's contructor! // Student's constructor! } } |
9、trait 继承 class
- 在Scala中trait 也可以继承 class,此时这个 class 就会成为所有继承该 trait 的子类的超级父类。
举例说明:
class MyUtil { def printMsg(msg: String) = println(msg) } trait Logger_Two extends MyUtil { def log(msg: String) = this.printMsg("log: " + msg) } class Person_Three(val name: String) extends Logger_Two { def sayHello { this.log("Hi, I'm " + this.name) this.printMsg("Hello, I'm " + this.name) } } object Person_Three{ def main(args: Array[String]) { val p=new Person_Three("Tom") p.sayHello //执行结果: // log: Hi, I'm Tom // Hello, I'm Tom } } |
scala当中的特质trait的更多相关文章
- Scala学习笔记--特质trait
http://outofmemory.cn/scala/scala-trait-introduce-and-example 与Java相似之处 Scala类型系统的基础部分是与Java非常相像的.Sc ...
- Scala学习十——特质
一.本章要点 类可以实现任意数量的特质 特质可以要求实现它们的类具备特定的字段,方法或超类 和Java接口不同,Scala特质可以提供方法和字段实现 当你将多个特质叠加在一起时,顺序很重要——其方法先 ...
- scala当中的类型参数
类型参数主要就是研究scala当中的类或者scala当中的方法的泛型 1.scala当中的类的泛型 object Demo8 { def main(args: Arr ...
- scala当中的对象
1.scala当中的Object 在scala当中,没有类似于像java当中的static修饰的静态属性或者静态方法或者静态代码块之类的,但是我们可以通过scala当中的Object来实现类似的功能. ...
- scala当中的文件操作和网络请求
1.读取文件当中每一行的数据 def main(args: Array[String]): Unit = { //注意文件的编码格式,如果编码格式不对,那么读取报错 val file: Buffere ...
- scala当中的类
1.类的定义与创建 创建一个scala class来定义我们的一个类.类当中可以定义各种属性或者方法,或者函数都可以 class Person { //定义一个属性,叫做name的 ...
- scala当中的Actor并发编程
注:Scala Actor是scala 2.10.x版本及以前版本的Actor. Scala在2.11.x版本中将Akka加入其中,作为其默认的Actor,老版本的Actor已经废弃. 1.什么是Sc ...
- scala学习手记31 - Trait
不知道大家对java的接口是如何理解的.在我刚接触到接口这个概念的时候,我将接口理解为一系列规则的集合,认为接口是对类的行为的规范.现在想来,将接口理解为是对类的规范多少有些偏颇,更恰当些的观点应该是 ...
- Beginning Scala study note(7) Trait
A trait provides code reusability in Scala by encapsulating method and state and then offing possibi ...
随机推荐
- Linq to SharePoint与权限提升(转)
转自http://www.cnblogs.com/kaneboy/archive/2012/01/25/2437086.html SharePoint 2010支持Linq to SharePoint ...
- Jquery Ajax 复杂json对象提交到WebService
在ajax的已不请求中,常常返回json对象.可以利用json.net给我们提供的api达到快速开发. 例子: using System;using System.Collections;using ...
- Linux 服务器 MySql的安装和网站的发布
Linux安装MySql,并配置能通过自己的电脑连接服务器的数据库 昨天安装的MySql,今天上午配置MySql能使用本机连接服务器数据库,服务器时DigitalOcean的,提供了很全面很专业的文档 ...
- 给Solr配置中文分词器
第一步下载分词器https://pan.baidu.com/s/1X8v65YZ4gIkNQXsXfSULBw 第二歩打开已经解压的ik分词器文件夹 将ik-analyzer-solr5-5.x.ja ...
- C#获取Url不同路径的方法大全
在 C# 中,用 Request 对象来获取 Url 的各种路径,包括上一页 Url.域名.绝对路径.相对路径和物理路径.虽然在某些情况下,无法获取到 Url,但可以获取到大部分情况下的 Url,下 ...
- SLF4+Logback 使用及配置
在SpringBoot项目中使用slf4+logback ①在pom.xml中添加依赖 <dependency> <groupId>ch.qos.logback</gro ...
- php index.php修改之后未生效
php index.php修改之后未生效 PHP项目修改了index.php 里面的代码,提交服务器之后,代码功能未生效, 解决办法:重启fpm 命令如下: /etc/init.d/php5-fpm ...
- dbUtils 中的各种 Handler 什么 意思
ArrayHandler:把结果集中的第一行数据转成对象数组. ArrayListHandler:把结果集中的每一行数据都转成一个对象数组,再存放到List中. BeanHandler:将结果集中的第 ...
- K:线性表的实现—顺序表
所谓顺序表,就是顺序存储的线性表.顺序存储就是用一组地址连续的存储单元依次存放线性表中各个数据元素的存储结构. 线性表中所有数据元素的类型是相同的,所以每一个数据元素在存储器中占用相同的大小的空间.假 ...
- Linux(Ubuntu)下MySQL的安装
1)首先检查系统中是否已经安装了MySQL 在终端里面输入 sudo netstat -tap | grep mysql 若没有反映,没有显示已安装结果,则没有安装.若如下显示,则表示已经安装 2)如 ...