第2节 Scala中面向对象编程:12、13、14、15、16、trait
6.4. Scala中面向对象编程之trait
6.4.1. 将trait作为接口使用
- Scala中的trait是一种特殊的概念;
- 首先先将trait作为接口使用,此时的trait就与Java中的接口 (interface)非常类似;
- 在trait中可以定义抽象方法,就像抽象类中的抽象方法一样,只要不给出方法的方法体即可;
- 类可以使用extends关键字继承trait,注意,这里不是 implement,而是extends ,在Scala中没有 implement 的概念,无论继承类还是trait,统一都是 extends;
- 类继承后,必须实现其中的抽象方法,实现时,不需要使用 override 关键字;
- Scala不支持对类进行多继承,但是支持多重继承 trait,使用 with 关键字即可。
- Class A extends class B
- Class A extends class C
- 举例说明:
package cn.itcast.triat
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
}
}
6.4.2. 在trait中定义具体的方法
- Scala中的trait不仅可以定义抽象方法,还可以定义具体的方法,此时 trait 更像是包含了通用方法的工具,可以认为trait还包含了类的功能。
- 举例说明:
- Scala 中的 trait 可以定义具体的 field,此时继承 trait 的子类就自动获得了 trait 中定义的 field;
- 但是这种获取 field 的方式与继承 class 的是不同的。 如果是继承 class 获取的 field ,实际上还是定义在父类中的;而继承 trait获取的 field,就直接被添加到子类中了。
- 举例说明:
package cn.itcast.triat
/**
* 比如 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]
}
}
6.4.3. 在trait中定义具体field
package cn.itcast.triat
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
}
}
6.4.4. 在trait中定义抽象field
- Scala中的trait也能定义抽象field, 而trait中的具体方法也能基于抽象field编写;
- 继承trait的类,则必须覆盖抽象field,提供具体的值;
- 举例说明:
package cn.itcast.triat
trait SayHelloTrait {
val msg:String
def sayHello(name: String) = 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)
}
}
6.4.5. 在实例对象指定混入某个trait
- 可在创建类的对象时,为该对象指定混入某个trait,且只有混入了trait的对象才具有trait中的方法,而其他该类的对象则没有;
- 在创建对象时,使用 with 关键字指定混入某个 trait;
- 举例说明:
- Scala中支持让类继承多个trait后,可依次调用多个trait中的同一个方法,只要让多个trait中的同一个方法,在最后都依次执行 super 关键字即可;
- 类中调用多个trait中都有的这个方法时,首先会从最右边的trait的方法开始执行,然后依次往左执行,形成一个调用链条;
- 这种特性非常强大,其实就是设计模式中责任链模式的一种具体实现;
- 案例说明:
package cn.itcast.triat
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.4.6. trait 调用链
package cn.itcast.triat
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
}
}
6.4.7. trait的构造机制
- 在Scala中,trait也是有构造代码的,即在trait中,不包含在任何方法中的代码;
- 继承了trait的子类,其构造机制如下:
- 父类的构造函数先执行, class 类必须放在最左边;多个trait从左向右依次执行;构造trait时,先构造父 trait,如果多个trait继承同一个父trait,则父trait只会构造一次;所有trait构造完毕之后,子类的构造函数最后执行。
- 举例说明:
package cn.itcast.triat
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!
}
}
6.4.8. trait 继承 class
- 在Scala中trait 也可以继承 class,此时这个 class 就会成为所有继承该 trait 的子类的超级父类。
- Class A
- Trait B extends A
- Class C extends B
- Trait D extends B
- 举例说明:
package cn.itcast.triat
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
}
}
第2节 Scala中面向对象编程:12、13、14、15、16、trait的更多相关文章
- 剑指offer19:按照从外向里以顺时针的顺序依次打印出每一个数字,4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
1 题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印 ...
- 第2节 Scala中面向对象编程:9、getClass和classOf;10、调用父类的constructor;11、抽象类和抽象字段;
6.3.4. Scala中getClass 和 classOf Class A extends class B B b=new A b.getClass ==classOf[A] B b ...
- 第2节 Scala中面向对象编程:7、继承的概念以及override和super关键字;8、isInstanceOf 和 asInstanceOf关键字
6.3. Scala面向对象编程之继承 6.3.1. Scala中继承(extends)的概念 Scala 中,让子类继承父类,与 Java 一样,也是使用 extends 关键字: 继承 ...
- 第2节 Scala中面向对象编程:1、类的定义;2、类的构造器;3、object和伴生对象;4、apply和main方法
6. 类.对象.继承.特质 Scala的类与Java.C++的类比起来更简洁,学完之后你会更爱Scala!!! 6.1. 类 6.1.1. 类的定义 package cn.itcast ...
- 【20171027中】alert(1) to win 第13,14,15,16题
第13题 题目: function escape(s) { var tag = document.createElement('iframe'); // For this one, you get t ...
- [.net 面向对象编程基础] (13) 面向对象三大特性——多态
[.net 面向对象编程基础] (13) 面向对象三大特性——多态 前面两节,我们了解了面向对象的的封装和继承特性,面向对象还有一大特性就是多态.比起前面的封装和继承,多态这个概念不是那么好理解.我们 ...
- Ubuntu LTS 系统学习使用体会和实用工具软件汇总 6.04 8.04 10.04 12.04 14.04 16.04
Ubuntu LTS 系统学习体会和工具软件汇总 6.04 8.04 10.04 12.04 14.04 16.04 ubuntu入门必备pdf:http://download.csdn.net/de ...
- TeamViewer 12\13\14 破解版(解决检测为商业用途的方式)
一.Windows系统下破解TeamViewer的方式 1.用Windows直接卸载本地的TeamViewer软件2.下载一个Everything软件,并安装好它(这是一个搜索本机文件的工具,超级好用 ...
- PHP中面向对象编程思想的3个特征
面向对象编程思想的3个特征: 封装: 无非是一个大的指向思想,目的是为了将一个类设计得更为健壮! 其基本做法是: 尽可能地将一个类的成员私有化,只开放那些必不可少的对外的属性或方法,能private的 ...
随机推荐
- Codeforces Round #579 (Div. 3) 题解
比赛链接:https://codeforc.es/contest/1203/ A. Circle of Students 题意:\(T\)组询问,每组询问给出\(n\)个数字,问这\(n\)个数字能否 ...
- MyBatis-Spring整合之方式1
导入相关包:Spring包:Spring架包 MyBatis包:MyBatis架包 整合包:Mybatis-Spring整合包 编写实体类User,实体类的sql映射文件,映射内容如下: <?x ...
- window下载并且安装kafka
安装zookeeper kafka运行需要有jdk+zookeeper环境才能够使用,jdk的安装和环境变量的配置就不介绍了,这里需要先安装zookeeper.可以从官网上下载 https://www ...
- 安卓开发:打印Log
在iOS开发中使用NSLog进行打印调试,在安卓中使用的是Log.v(tag, msg);等进行打印调试. 参考:[https://blog.csdn.net/salary/article/detai ...
- 对DensePose: Dense Human Pose Estimation In The Wild的理解
研究方法 通过完全卷积学习从图像像素到密集模板网格的映射.将此任务作为一个回归问题,并利用手动注释的面部标注来训练我们的网络.使用这样的标注,在三维对象模板和输入图像之间,建立密集的对应领域,然后作为 ...
- vscode解决java无法输入(scanner)问题
vscode解决java无法输入问题 需要先安装java环境,->windows安装java 新建Test.java 输入代码 import java.util.Scanner; public ...
- mysql免安装版配置启动时出错
今天安装了MySQL5.7的免安装版本,启动时报了服务无法启动的错误,在网上找了好久终于找到了解决方法 我找到解决方法的博客地址是:http://blog.csdn.net/qq_27093465/a ...
- 解决IDEA快捷键 Alt+Insert 失效的问题
现象 IDEA快捷键 Alt+Inser 失效,单击右键也不出现[Generate]. 这个问题经常出现在重新安装IDEA后. 原因 缺少2个插件 解决办法 在setting中启用这2个插件即可.这2 ...
- Druid数据源SQL数据库与Spring监控
Druid监控概要说明 为什么要监控? Druid是什么?德鲁伊 URL监控配置说明 配置步骤 步骤 配置 第一步 web.xml 配置 WebStatFilter 第二步 WebStatFilter ...
- Fluent_Python_Part2数据结构,03-dict-set,字典和集合
字典和集合 dict和set都基于hash table实现 1. 大纲: 常见的字典方法 如何处理查找不到的键 标准库中dict类型的变种 set和fronzenset类型 Hash table的工作 ...