scala学习笔记11 特质
2016-08-09 23:09
393 查看
本章要点:
一个类扩展自一个或者多个特质,以便使用这些特质提供的服务。特质可能会要求它的类支持某个特定的特性,和java接口不同,scala特质可以给出这些特性的缺省实现。
类可以实现任意数量的特质特质可以要求实现他们的类具有特定的字段,方法或者超类
和java接口不一样,scala特质可以提供方法和字段的实现
当你将多个特质叠加在一起时,顺序很重要---方法先被执行的特质排在后面
1、为什么没有多重继承?
scala和java一样,不允许类从多个超类继承,因为如果多重继承的类具有某些共通的方法或字段,就会出现无法辨明使用哪个方法或者字段。
接下来,假设student和employee都继承自同一个超类person
class Person {
var name:String= _
}
class student extends Person{}
class Employee extends Person{}
这就引入了菱形继承问题。在teachassistant中我们只想一个name字段,而不是两个。(java的类可以实现任意的数量的借口,但借口只能包含抽象方法,不能包含字段)
特质可以同时具有抽象方法和具体方法,而类可以实现多个特质。
2、当作接口使用的特质
trait Logger {
def log(msg:String) //抽象方法,特质中未被实现的方法默认是抽象的
}
class ConsoleLogger extends Logger {
def log(msg:String) {println(msg)} //不需要override
}
比起java的借口,特质和类更为相似。
如果你需要的特质不止一个,可以用with关键字来添加额外的特质:
class ConsoleLogger extends Logger with Cloneable with Serializable
这里使用java类库的两种接口,所有的java接口都可以当成scala特质使用。
总结:scala类只能有一个超类但是可以有任意数量的特质。
3、带有具体实现的特质
trait ConsoleLogger{
def log(msg:String) {}
}
以下是如何使用这个特质的示例
savingaccount从consolelogger特质得道一个log方法,java接口不能做到。
4、带有特质的对象
trait Logged {def log(msg:String){}
}
上面的类看上去毫无意义,但是在构造具体对象时可以混入一个更好的日志记录器的实现。
trait ConsoleLogger extends logged{
override def log(msg:String) {}
}
可以在构造对象时加入特质:
val acct=new savingaccount with consolelogger
还可以在另一个对象上加入不同的特质
val acct2=new savingaccount with filelog
5、叠加在一起的特质你可以为类或者对象添加多个互相调用的特质,从最后一个开始。
首先,加时间戳
注意上述的log方法将每一个修改过的消息传递给super.log。
对于特质而言,super.log并不想类那样拥有相同的含义。(实际上,logged中的log函数毫无用处)实际上,super.log调用的是特质层级下一个特质。
可以利用super[consolelogger].log(...)规定哪一个特质的方法被调用。
这篇文章里的例子很好:http://blog.csdn.net/o1101574955/article/details/51815018
6、在特质中重写抽象方法
先引入一个没有被实现的logger特质
trait Logger {
def log(msg:String) }
现在使用时间戳特质来扩展它
trait TimestampLogger extends Logger {
override def log(msg:String){
super.log(new java.util.Date()+" "+msg) }
}
但是在编译时会将super.log标记为错误。因为根据正常的继承规则,Logger.log没有被实现,我们无法知道哪个log最终被调用。scala认为TimestampLogger仍旧是抽象的,它需要混入一个具体的log方法,所以需要在方法上打上abstract关键字和override关键字。
7、当作富接口使用的特质
特质可以包含大量工具方法,而这些工具方法可以依赖一些抽象方法来实现,例如scala的Iterator特质就利用抽象的next和hasNext定义了几十个方法。
trait Logger {
def log(msg:String)
def info(msg:String) { log("INFO:"+msg)}
def warn(msg:String) { log("WARN:"+msg) }
def severe(msg:String) { log("SEVERE:"+msg) }
}
这样一来,我们可以使用logger特质任意调用这些log的方法:
8、特质中的具体字段
特质中的字段可以是具体的,也可以是抽象的,如果你给出了初始值,那么字段就是具体的。
trait ShortLogger extends Logged {
val maxLength =15 }
混入该特质的类自动获得一个maxlebgth字段。通常,对于特质中的每个字段,使用该特质的类都会获得一个字段与之对应,这些字段不是被继承的,只是简单的被加到子类中。
class SavingAccount extends Account with ConsoleLogger with ShortLogger {
var intesest=0.0
...
}
class Account {
var balance=0.0
}
savingaccount类以正常的方式继承了balance字段。但是对于maxlength字段,则不一样。
9、特质中的抽象字段
特质中未被初始化的字段在具体的子类中必须被重写。
如下maxLength字段是抽象的:trait ShortLogger extends Logged {
val maxLength:Int
override def log(msg:String) {
super.log(if (msg.length<=maxLength)) msg else mag.substring(0,maxLength-3)+"...")
}
...}
当你在一个具体的类中使用该特质时,必须提供maxlength字段。
class SavingAccount
ba61
extends Account with ConsoleLogger with ShortLogger {
val maxLength=20 //不需要override
...}
这种提供特质参数的方式十分的方便,比如:
val acct=new SavingAccount with ConsoleLogger with ShortLogger {val maxLength=20
} //注意下文11,这种方法似乎存在问题??
10、特质构造顺序
和类一样,特质也可以有构造器,由字段的初始化和其它特质体中的语句构成。例如:
trait FileLogger extends Logger {
val out=new PrintWriter("app.log")
out.println("#"+new Date().toString) //这是特质构造器的一部分
def log(msg:String) { out.println(msg) ; out.flush() } //这是特质构造器的一部分
}
这些语句在任何混入该特质的对象在构造时都会被执行。
构造器以如下顺序执行:
举例来说,考虑如下一个类的构造顺序
class SavingAccount extends Account with FileLogger with ShortLogger
11、初始化特质中的字段
特质不能有构造器参数,每个特质都有一个无参数的构造器。
注意点:缺少构造器参数是特质与类之间唯一的技术差别。除此之外,特质可以具备类的所有特性,比如具体的和抽象的字段以及超类。
val acct=new SavingAccount with FileLogger("myapp.log")
//错误:特质不能够使用构造器参数
trait FileLogger extends Logger {
val filename:String
val out=new printwriter(filename)
....}
使用该特质的类可以重写filename字段,不过下面的方案并不可行:
val acct=new SavingAccount with FileLogger {
val filename = "myapp.log" //错误
}
12、扩展类的特质
trait a extends b {}
class c extends a{}
如上,假设一个特质a继承一个类b,类c继承a,则b自动成为c的超类。但是如果c还extends另外一个类,怎么办?
只要这两个类是b的子类就行。
13、背后发生了什么?
scala需要将特质翻译成jvm的接口和类
相关文章推荐
- Windows下Scala环境搭建
- Windows7下安装Scala 2.9.2教程
- Scala代码实现列出Hadoop 文件夹下面的所有文件
- ClassNotFoundException:scala.PreDef$
- sbt创建web项目
- XML 文件解析--含Unicode字符的XML文件
- Scala 学习随笔
- Scala 小程序记录(学习期间的代码片段)
- Spark机器学习(二) 局部向量 Local-- Data Types - MLlib
- Spark机器学习(三) Labeled point-- Data Types
- 分分钟掌握快速排序(Java / Scala 实现)
- Scala极速入门
- Spark初探
- Scala实现REST操作
- Scala method call syntax
- 关于Scala多重继承的菱形问题
- Scala 高阶函数(high-order function)剖析
- Scala Monad Design Pattern
- Scala类型系统——高级类类型(higher-kinded types)
- Spray.io搭建Rest服务