scala学习笔记-特质

1. 为什么没有多重继承

scala和java一样不允许类从多个超类继承。
但是scala提供“特质”而非接口。特质可以同时拥有抽象方法和具体方法,而类可以实现多个特质。

2. 当做接口使用的特质

scala特质完全可以像java接口那样工作。例如:
trait Logger{
     def log(msg:String)//抽象方法
}

不需要将方法声明为abstract——特质中未被实现的方法默认为抽象方法
子类可以给出实现:
class ConsoleLogger extends Logger{//使用extends而非implements
      def log(msg:String){ println(msg)}//不需要写override
}

如果需要多个特质,可以用with关键字来添加额外的特质:
class ConsoleLogger extends Logger with Cloneable with Serializable
所有java中的接口都可以作为scala特质使用。
Scala类只能继承一个超类,但可以有任意数量的特质

3. 带有具体实现的特质

scala中,特质中的方法并不需要一定是抽象的。例如:
trait ConsoleLogger{
   def log(msg:String){println(msg)
}
ConsoleLogger特质提供了一个带有实现的方法

4. 带有特质的对象

例如scala标准库中logged特质:
trait Logged{
   def log(msg:String){)
}
可以扩展logged特质:
trait ConsoleLogger extends Logged{
   override def log(msg:String){println(msg)
}
可以在构造对象时,添加特质。可以在acct对象上调用log方法。
val acct=new SavingAccount with ConsoleLogger
也可以在另一个对象上加入不同特质。
val acct2=new SavingAccount with FileLogger

5. 叠加在一起的特质

可以为类或者对象添加多个互相调用的特质,从最后一个开始。这对于需要分阶段加工处理某个值的场景很有用。
例如:需要给所有日志消息添加时间戳:
trait TimestampLogger extends Logged{
   override def log(msg:String){
       super.log(new java.util.Date()+" "+ msg)
   }
}
需要截断过长的日志消息:
trait ShortLogger extends Logged{
   override def log(msg:String){
       super.log( 
          if(msg.length<15) msg else msg.substring(0,15-3)+"... ") 
    }
}

例如:

val acct1=new SavingAccount with ConsoleLogger with TimestampLogger with ShortLogger
val acct2=new SavingAccount with ConsoleLogger with ShortLogger  with TimestampLogger 
acct1取款: Sun Feb 06 17:45:45 ICT 2017 Instufficient...    //shortlogger先执行
acct2取款: Sun Feb 06 1...    //timestamplogger先执行

6. 在特质中重写抽象方法

trait TimestampLogger extends Logger{
   override def log(msg:String){
       super.log(new java.util.Date()+" "+ msg)
   }
}
编译器将super.log调用标记为错误
scala认为TimestampLogger依旧是抽象的,需要混入一个具体的log方法。因此正确方法:
trait TimestampLogger extends Logger{
   abstract override def log(msg:String){
       super.log(new java.util.Date()+" "+ msg)
   }
}

7. 当做富接口使用的特质

特质可以包含大量工具方法,而这些工具方法可以依赖一些抽象方法来实现8

8. 特质中的具体字段

特质中的字段可以是具体的,也可以是抽象的。若给出初始值,则字段是具体的。对于特质中的每一个具体字段,使用该特质的类都会获得一个字段与之对应。这些字段不是被继承的;只是简单地被加到子类当中

9. 特质中的抽象字段

特质中未被初始化的字段在具体的子类中必须被重写。

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()}
}
构造器以如下顺序执行:
  • 首先调用超类的构造器
  • 特质构造器在超类构造器之后、类构造器之前执行
  • 特质由左到右被构造
  • 每个特质当中,父特质先被构造
  • 如果多个特质共有一个父特质,而那个父特质已经被构造,则不会被再次构造
  • 所有特质构造完毕,子类被构造

11. 初始化特质中的字段

特质不能有构造参数。每个特质都有一个无参数的构造器。

12. 扩展类的特质

特质可以扩展另一个特质,而特质组成的继承层级也很常见。特质也可以扩展类。这个类会自动成为所有混入该特质的超类。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值