Scala基础:面向对象之trait
trait类似于java中的interface,但是有所不同
- Scala中的trait是一种特殊的概念;
- 首先先将trait作为接口使用,此时的trait就与Java中的接口 (interface)非常类似;
- 在trait中可以定义抽象方法,就像抽象类中的抽象方法一样,只要不给出方法的方法体即可;
- 类可以使用extends关键字继承trait,注意,这里不是 implement,而是extends ,在Scala中没有 implement 的概念,无论继承类还是trait,统一都是 extends;
- 类继承后,必须实现其中的抽象方法,实现时,不需要使用 override 关键字;
- Scala不支持对类进行多继承,但是支持多重继承 trait,使用 with 关键字即可。
- package com.zy.scala.trait_demo
- 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
- }
- }
在trait中定义具体的方法
Scala中的trait不仅可以定义抽象方法,还可以定义具体的方法,此时 trait 更像是包含了通用方法的工具,可以认为trait还包含了类的功能
- package com.zy.scala.trait_demo
- /**
- * 比如 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]
- }
- }
在trait中定义具体field
- Scala 中的 trait 可以定义具体的 field,此时继承 trait 的子类就自动获得了 trait 中定义的 field;
- 但是这种获取 field 的方式与继承 class 的是不同的。 如果是继承 class 获取的 field ,实际上还是定义在父类中的;而继承 trait获取的 field,就直接被添加到子类中了。
- package com.zy.scala.trait_demo
- 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
- }
- }
在trait中定义抽象field
- Scala中的trait也能定义抽象field, 而trait中的具体方法也能基于抽象field编写;
- 继承trait的类,则必须覆盖抽象field,提供具体的值;
- package com.zy.scala.trait_demo
- 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)
- }
- }
在实例对象指定混入某个trait
- 可在创建类的对象时,为该对象指定混入某个trait,且只有混入了trait的对象才具有trait中的方法,而其他该类的对象则没有;
- 在创建对象时,使用 with 关键字指定混入某个 trait;
- package com.zy.scala.trait_demo
- 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!
- }
- }
trait 调用链
- Scala中支持让类继承多个trait后,可依次调用多个trait中的同一个方法,只要让多个trait中的同一个方法,在最后都依次执行 super 关键字即可;
- 类中调用多个trait中都有的这个方法时,首先会从最右边的trait的方法开始执行,然后依次往左执行,形成一个调用链条;
- 这种特性非常强大,其实就是设计模式中责任链模式的一种具体实现;
- package com.zy.scala.trait_demo
- 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
- }
- }
混合使用 trait 的具体方法和抽象方法
- 在 trait 中,可以混合使用具体方法和抽象方法;
- 可以让具体方法依赖于抽象方法,而抽象方法则可放到继承 trait的子类中去实现;
- 这种 trait 特性,其实就是设计模式中的模板设计模式的体现;
- package com.zy.scala.trait_demo
- 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)
- }
- }
trait的构造机制
- 在Scala中,trait也是有构造代码的,即在trait中,不包含在任何方法中的代码;
- 继承了trait的子类,其构造机制如下:
- 父类的构造函数先执行, class 类必须放在最左边;多个trait从左向右依次执行;构造trait时,先构造父 trait,如果多个trait继承同一个父trait,则父trait只会构造一次;所有trait构造完毕之后,子类的构造函数最后执行。
- package com.zy.scala.trait_demo
- 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!
- }
- }
trait 继承 class
- package com.zy.scala.trait_demo
- 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的更多相关文章
- 第2节 Scala中面向对象编程:12、13、14、15、16、trait
6.4. Scala中面向对象编程之trait 6.4.1. 将trait作为接口使用 Scala中的trait是一种特殊的概念: 首先先将trait作为接口使用,此时的trait就与Java ...
- 【Scala学习之一】 Scala基础语法
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 scala-2.10.4(依赖jdk1.8) spark ...
- 1.scala基础语法总结
Scala基础语法总结:Scala 与 Java 的最大区别是:Scala 语句末尾的分号 ; 是可选的.如果一行里写多个语句那么分号是需要的 val s = "菜鸟教程"; pr ...
- Scala基础简述
* Scala基础简述 本文章作为Scala快速学习的教程,前提环境是:我假设在此之前,你已经学会了Java编程语言,并且我们以随学随用为目标(在此不会深度挖掘探讨Scala更高级层次的知识).其中语 ...
- Scala之面向对象
1. Scala基础练习 不使用str.toLong,str.toInt/Integer.valueOf()/Long.valueOf/Integer.parseInt()等,将字符串"12 ...
- Scala学习笔记--特质trait
http://outofmemory.cn/scala/scala-trait-introduce-and-example 与Java相似之处 Scala类型系统的基础部分是与Java非常相像的.Sc ...
- spark快速开发之scala基础之1 数据类型与容器
写在前面 面向java开发者.实际上,具有java基础学习scala是很容易.java也可以开发spark,并不比scala开发的spark程序慢.但学习scala可有助于更快更好的理解spark.比 ...
- 大数据技术之_16_Scala学习_04_函数式编程-基础+面向对象编程-基础
第五章 函数式编程-基础5.1 函数式编程内容说明5.1.1 函数式编程内容5.1.2 函数式编程授课顺序5.2 函数式编程介绍5.2.1 几个概念的说明5.2.2 方法.函数.函数式编程和面向对象编 ...
- Scala基础知识[一]
摘要:在Scala 是 Scalable Language 的简写,是一门多范式(multi-paradigm)的编程语言.设计初衷是要集成面向对象编程和函数式编程的各种特性.Scala 运行在Jav ...
- SCALA基础知识学习
注:本文只说和Java不同的地方. 总结自: Scala详细教程 Scala教程 scala基础语法 Scala 与 Java 的最大区别是:Scala 语句末尾的分号 ";" 是 ...
随机推荐
- Django的MultipleChoiceField处理小技巧
1.如果遇到多选择的,在收到数据时一般需要做处理 tag_id = fields.MultipleChoiceField( choices=[], widget=widgets.CheckboxSel ...
- OpenStack_Swift源代码分析——Ring的rebalance算法源代码具体分析
1 Command类中的rebalnace方法 在上篇文章中解说了,创建Ring已经为Ring加入设备.在加入设备后须要对Ring进行平衡,平衡 swift-ring-builder object.b ...
- 虚拟主机wordpress文件上传大小限制更改
默认的wp文件上传的大小都是2M 登录阿里云进入控制面板找到你的虚拟机实例 点击管理 改成10M,最大也就是10,虚拟机的睾丸之处.保存,去页面新媒体添加可以看到最大限制为10M了
- stm32f0系列在SWD模式下载时复位失败
用stm32f030K6T6做了个小玩意,仿真电路就直接把3.3V,SWDIO,SWCLK,GND引出来连接到j-link的这四个角上,SWDIO和SWCLK引脚既没有上拉也没有下拉. MCU ...
- 【转】redis GEO地理位置
redis目前已经到了3.2版本,3.2版本里面新增的一个功能就是对GEO(地理位置)的支持. 地理位置大概提供了6个命令,分别为: GEOADD GEODIST GEOHASH GEOPOS GEO ...
- kafka 经典教程
一.基本概念 介绍 Kafka是一个分布式的.可分区的.可复制的消息系统.它提供了普通消息系统的功能,但具有自己独特的设计. 这个独特的设计是什么样的呢? 首先让我们看几个基本的消息系统术语: Kaf ...
- 杂项:NoSQL
ylbtech-杂项:NoSQL NoSQL,泛指非关系型的数据库.随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站 ...
- 读取web外的配置文件
一般web项目配置文件都放在classPath下面,读取的时候: 1 import java.io.InputStream; 2 import java.util.Properties; 3 publ ...
- 第十三章 hadoop机架感知
背景 分布式的集群通常包含非常多的机器,由于受到机架槽位和交换机网口的限制,通常大型的分布式集群都会跨好几个机架,由多个机架上的机器共同组成一个分布式集群.机架内的机器之间的网络速度通常都会高于跨机架 ...
- linux 下查找文件或者内容常用命令
转自:http://www.cnblogs.com/sunleecn/archive/2011/11/01/2232210.html whereis <程序名称>查找软件的安装路径-b 只 ...