Spark基础-scala学习(三、Trait)
面向对象编程之Trait
trait基础知识
- 将trait作为接口使用
- 在trait中定义具体方法
- 在trait中定义具体字段
- 在trait中定义抽象字段
trait高级知识
- 为实例对象混入trait
- trait调用链
- 在trait中覆盖抽象方法
- 混合使用trait的具体方法和抽象方法
- trait的构造机制
- trati字段的初始化
- 让trait继承类
将trait作为接口使用
- trait作为接口,和java中的接口非常类似
- 在triat中可以定义抽象方法,就与抽象类中的抽象方法一样,只要不给出方法的具体实现即可
- 类可以使用extends关键字继承trait,注意,这里不是implement,而是extends,在scala中没有implement的概念,无论继承类还是trait,统一都是extends
- 类继承trait后,必须实现其中的抽象方法,实现时不需要使用override关键字
- scala不支持对类进行多继承,而是支持多重继承trait,使用with关键字即可
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait HelloTrait{
def sayHello(name:String)
}
trait MakeFriendsTrait{
def makeFriend(p:Person)
}
class Person(val name:String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable
{
def sayHello(name:String) = println("Hello," + name)
def makeFriend(p:Person) = println("Hello,my name is "+name +",your name is "+p.name)
}
// Exiting paste mode, now interpreting.
defined trait HelloTrait
defined trait MakeFriendsTrait
defined class Person
scala> val p = new Person("Tom")
p: Person = Person@41eb94bc
scala> p.makeFriend(p)
Hello,my name is Tom,your name is Tom
scala> p.sayHello("jike")
Hello,jike
在Trait中定义具体的方法
- scala中的Triat可以不是只定义抽象方法,还可以定义具体方法,此时trait更像是包含了通用工具方法的东西
- 就想trait的功能混入了类
- 举例来说,trait中可以包含一些很多类都通用的功能方法,比如打印日志等等,spark中就使用了trait来定义了通用的日志打印方法
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait Logger{
def log(message :String) = println(message)
}
class Person(val name:String) extends Logger{
def makeFriends(p:Person){
println("Hi,I'm "+name+",I'm glad to make friends with you," + p.name)
log("makeFriends method is invoked with parameter Person[name="+p.name+"]")
}
}
// Exiting paste mode, now interpreting.
defined trait Logger
defined class Person
scala> val p = new Person("Tom")
p: Person = Person@6a6e9289
scala> p.makeFriends(p)
Hi,I'm Tom,I'm glad to make friends with you,Tom
makeFriends method is invoked with parameter Person[name=Tom]
在trait中定义具体字段
- scala中trait可以定义具体field,此时继承trait的类就可以自动获得trait中定义的field
- 但是这种获取field的方式与继承class是不同的:如果是继承class获得的field,实际是定义在父类中的;而继承trait获取的field,就直接被添加到类中
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait Person{
val eyeNum:Int = 2
}
class Student(val name:String) extends Person{
def sayHello = println("Hi,I'm "+name+",I have "+eyeNum+" eyes")
}
// Exiting paste mode, now interpreting.
defined trait Person
defined class Student
scala> val s = new Student("Tom")
s: Student = Student@12765ebd
scala> s.sayHello
Hi,I'm Tom,I have 2 eyes
在Trait中定义抽象字段
- scala中的Trait可以定义抽象field,而trait中的具体方法则可以基于抽象field来编写
- 但是继承trait的类,则必须覆盖抽象field,提供具体的值
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait SayHello{
val msg:String
def sayHello(name:String) = println(msg+","+name)
}
class Person(val name:String) extends SayHello{
val msg:String = "hello"
def makeFriends(p:Person){
sayHello(p.name)
print("I'm "+name+",I want to make friends with you!")
}
}
// Exiting paste mode, now interpreting.
defined trait SayHello
defined class Person
scala> val p = new Person("Tom")
p: Person = Person@67cd193d
scala> p.msg
res4: String = hello
scala> p.makeFriends(p)
hello,Tom
I'm Tom,I want to make friends with you!
为实例混入trait
- 有时候我们可以在创建类的对象时,指定该对象混入某个trait,这样,就只有这个对象混入该trait的方法,而类的其他对象则没有
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait Logged{
def log(msg:String){}
}
trait MyLogger extends Logged{
override def log(msg:String){println("log:"+msg)}
}
class Person(val name:String) extends Logged{
def sayHello{println("Hi,I'm "+name);log("sayHello is invoked!")}
}
// Exiting paste mode, now interpreting.
defined trait Logged
defined trait MyLogger
defined class Person
scala> val p1 = new Person("leo")
p1: Person = Person@20307cb9
scala> p1.sayHello
Hi,I'm leo
scala> val p2 = new Person("jack") with MyLogger
p2: Person with MyLogger = $anon$1@192800d
scala> p2.sayHello
Hi,I'm jack
log:sayHello is invoked!
trait调用链
- scala中支持多个trait,一次调用多个trait中的同一个方法,只要让多个trait的同一个方法中,在最后都执行super.方法即可
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait Handler{
def handle(data:String){}
}
trait DataValidHandler extends Handler{
override def handle(data:String){
println("check data:" +data)
super.handle(data)
}
}
trait SignatureValidHandler extends Handler {
override def handle(data:String){
println("check signature: "+data)
super.handle(data)
}
}
class Person(val name:String) extends SignatureValidHandler with DataValidHandler{
def sayHello = { println("Hello, " + name);handle(name)}
}
// Exiting paste mode, now interpreting.
defined trait Handler
defined trait DataValidHandler
defined trait SignatureValidHandler
defined class Person
scala> val p1 = new Person("Tom")
p1: Person = Person@5fefb35c
scala> p1.sayHello
Hello, Tom
check data:Tom
check signature: Tom
在trait中覆盖抽象方法
- 在trait中,是可以覆盖父trait的抽象方法的
- 但是覆盖时,如果使用了super.方法的代码,则无法通过编译。因为super.方法就会去调用父trait的抽象方法,此时子trait的该方法还是会被认为是抽象的
- 此时如果要通过编译,就得给子trait的方法加上abstract override修饰
trait Logger{
def log(msg:String)
}
trait MyLogger extends Logger{
abstract override def log(msg:String) {super.log(msg)}
}
混合使用trait的具体方法和抽象方法
- 在trait中,可以混合使用具体方法和抽象方法
- 可以让具体方法依赖于抽象方法,而抽象方法则放到继承trait的类中去实现
- 这种trait其实就是设计模式中的模板设计模式的体现
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait Valid{
def getName:String
def valid:Boolean = {
getName == "leo"
}
}
class Person(val name:String) extends Valid{
println(valid)
def getName = name
}
// Exiting paste mode, now interpreting.
defined trait Valid
defined class Person
scala> val p = new Person("leo")
true
p: Person = Person@30749de8
scala> p.getName
res10: String = leo
scala> val p2 = new Person("Tom")
false
p2: Person = Person@622a4589
scala> p2.getName
res11: String = Tom
trait的构造机制
- 在scala中,trait也是有构造代码的,也就是trait中,不包含在任何方法中的代码
- 而继承了trait的类的构造机制如下
- 父类的构造函数执行
- trait的构造代码执行,多个trait从左到右依次执行
- 构造trait时会先构造父trait,如果多个trait继承同一个父trait,则父trait只会构造一次
- 所有trait构造完毕之后,子类的构造函数执行
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Person{println("Person constructor")}
trait Logger{println("Logger constructor")}
trait MyLogger extends Logger{println("MyLogger constructor")}
trait TimeLogger extends Logger{println("TimeLogger constructor")}
class Student extends Person with MyLogger with TimeLogger{
println("Student constructor")
}
// Exiting paste mode, now interpreting.
defined class Person
defined trait Logger
defined trait MyLogger
defined trait TimeLogger
defined class Student
scala> val s = new Student
Person constructor
Logger constructor
MyLogger constructor
TimeLogger constructor
Student constructor
s: Student = Student@22caeb7f
trait field的初始化
- 在scala中,trait是没有接受参数的构造函数的,这是trait与clas的唯一区别,但是如果需求就是要trait能够对field进行初始化,我们可以使用scala中非常特殊的一种高级特性--提前定义
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait SayHello{
val msg:String
println(msg:String)
}
class Person
val p = new {
val msg:String = "init"
} with Person with SayHello
// Exiting paste mode, now interpreting.
init
defined trait SayHello
defined class Person
p: Person with SayHello = $anon$1@6ce7fb0c
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Person extends{
val msg:String = "init"
} with SayHello{}
// Exiting paste mode, now interpreting.
defined class Person
scala> val p2 = new Person
init
p2: Person = Person@16c87aa2
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait SayHello{
lazy val msg:String = null
println(msg.toString)
}
class Person extends SayHello{
override lazy val msg:String = "init"
}
// Exiting paste mode, now interpreting.
defined trait SayHello
defined class Person
scala> val p3 = new Person
init
p3: Person = Person@3219b550
trait继承class
- 在scala中,trait也可以继承自class,此时这个class就会为所有继承该trait的类的父类
scala> :paste
// Entering paste mode (ctrl-D to finish)
class MyUtil{
def printMessage(msg:String) = println(msg)
}
trait Logger extends MyUtil{
def log(msg:String) = printMessage("log: "+msg)
}
class Person(val name:String) extends Logger{
def sayHello{
log("Hi,I'm "+name)
printMessage("Hi,I'm "+name)
}
}
// Exiting paste mode, now interpreting.
defined class MyUtil
defined trait Logger
defined class Person
scala> val p = new Person("Jike")
p: Person = Person@3685cd73
scala> p.sayHello
log: Hi,I'm Jike
Hi,I'm Jike
Spark基础-scala学习(三、Trait)的更多相关文章
- Spark基础-scala学习(二、面向对象)
面向对象编程之类 //定义一个简单的类 scala> :paste // Entering paste mode (ctrl-D to finish) //类默认public的 class He ...
- Spark基础-scala学习(五、集合)
集合 scala的集合体系结构 List LinkedList Set 集合的函数式编程 函数式编程综合案例:统计多个文本内的单词总数 scala的集合体系结构 scala中的集合体系主要包括:Ite ...
- Spark基础-scala学习(一、入门)
Scala解析器的使用 REPL:Read(取值)-> Evaluation(求值)-> Print(打印)->Loop(循环).scala解析器也被称为REPL,会快速编译scal ...
- Spark基础-scala学习(八、隐式转换与隐式参数)
大纲 隐式转换 使用隐式转换加强现有类型 导入隐式转换函数 隐式转换的发生时机 隐式参数 隐式转换 要实现隐式转换,只要程序可见的范围内定义隐式转换函数即可.Scala会自动使用隐式转换函数.隐式转换 ...
- Spark基础-scala学习(七、类型参数)
类型参数是什么 类似于java泛型,泛型类 泛型函数 上边界Bounds 下边界 View Bounds Context Bounds Manifest Context Bounds 协变和逆变 Ex ...
- Spark基础-scala学习(四、函数式编程)
函数式编程 将函数赋值给变量 匿名函数 高阶函数 高级函数的类型推断 scala的常用高阶函数 闭包 sam转换 currying函数 return 将函数赋值给变量 scala中的函数是一等公民,可 ...
- Spark之Scala学习
1. Scala集合学习: http://blog.csdn.net/lyrebing/article/details/20362227 2. scala实现kmeans算法 http://www.t ...
- Scala学习(三)----数组相关操作
数组相关操作 摘要: 本篇主要学习如何在Scala中操作数组.Java和C++程序员通常会选用数组或近似的结构(比如数组列表或向量)来收集一组元素.在Scala中,我们的选择更多,不过现在我们先假定不 ...
- Scala学习三——数组相关操作
一.若长度固定则使用Array,若长度可能有变化则使用ArrayBuffer 固定长度数组: 如val nums=new Array[Int](10) //10个整型数组,所有元素初始化为0; val ...
随机推荐
- gitlab 误关闭sign-in
sudo gitlab-rails console ApplicationSetting.last.update_attributes(password_authentication_enabled_ ...
- char对比varchar
char对比varchar 相同点:char与varchar都是存储字符串的数据类型 不同点:char是固定长度的字符类型,而varchar是可变长度的字符类型,这个一定要注意.另外进行select时 ...
- mac电脑Git提交代码到Github提示git-credential-osxkeychain 验证解决方案
## 啊哈哈 这个简单,直接给出当前mac电脑登录账号密码即可,^_*,拿走不谢!!
- C# WPF 父控件通过使用可视化树找到子控件
在我们使用WPF设计前台界面时,经常会重写数据模板,或者把控件放到数据模板里.但是一旦将控件放到数据模板中,在后台就没有办法通过控件的名字来获取它了,更没办法对它进行操作(例如,隐藏,改变控件的某个值 ...
- chrome gps位置模拟设置
chrome gps位置模拟设置 调试公众号页面定位,Edge 虽好实现方便,介于界面实在不符合我的调试习惯 遂上度娘寻觅chrome模拟GPS方法 找了好几个帖子,发现新版本已经不再试用.不得感叹 ...
- xbee3的先进性功能用法
xbee3以及xbee3 PRO 是digi无线模块的又一大突破:不仅实现了所有2.4G的模块整合,更在以后的程序更新中会增加蓝牙功能:它打通了xbee系列1和系列2之间的壁垒:不同于xbee S2C ...
- 浅谈React数据流管理
引言:为什么数据流管理如此重要?react的核心思想就是:UI=render(data),data就是我们说的数据流,render是react提供的纯函数,所以用户界面的展示完全取决于数据层.这篇文章 ...
- Shiro与Spring整合
Shiro引入Spring 添加jar包/maven配置 <!-- shiro支持 --> <dependency> <groupId>org.apache.shi ...
- 2019.03.26 bzoj4448: [Scoi2015]情报传递(归并排序+树链剖分)
传送门 题意简述: 给一棵nnn个点的树,树上每个点表示一个情报员,一共有mmm天,每天会派发以下两种任务中的一个任务: 1.搜集情报:指派T号情报员搜集情报 2.传递情报:将一条情报从X号情报员传递 ...
- LOJ-10092(最大半连通子图)
题目连通:传送门 思路: 题目定义很清晰,然后就不会了QAQ…… 后来看了书,先缩点,然后再用拓扑排序找到最长的链子的节点数(因为缩点后所有点都是一个强连通分量,所以找最长的链子就是最大限度包含 点的 ...