scala学习笔记11 特质

本章要点:
一个类扩展自一个或者多个特质,以便使用这些特质提供的服务。特质可能会要求它的类支持某个特定的特性,和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 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的接口和类















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值