scala的继承、组合与特质trait

scala可以在子类的构造器中重写父类的属性,例如:
abstract class Element{
def contents :Array[ String ]
val height :Int = contents . length
val width :Int = if ( height == 0 ) 0 else contents ( 0 ). length
}
子类:
class UniformElement( u :Char, override val width :Int, override val height :Int) extends Element{
private val line = u . toString () * width
def contents = Array . fill ( height )( line )
}
可以看到父类的height、width在子类的构造器中,以参数的形式被重写了。
聚义例子:
import Element. elem

abstract class Element{
def contents :Array[ String ]
def height :Int = contents . length
def width :Int = if ( height== 0 ) 0 else contents ( 0 ). length
def above ( that :Element):Element=
elem ( this . contents++ that . contents )
def beside ( that :Element):Element={
elem ( for (( line1 , line2 ) <- this . contents zip that . contents ) yield line1 + line2 )
}
override def toString = contents mkString "/n"
}

object Element {
private class ArrayElement( val contents :Array[ String ]) extends Element
private class LineElement( s : String ) extends Element{
val contents = Array ( s )
override def width = s . length
override def height = 1
}
private class UniformElement( u :Char, override val width :Int, override val height :Int) extends Element{
private val line = u . toString () * width
def contents = Array . fill ( height )( line )
}
def elem ( contents :Array[ String ]):Element=
new ArrayElement( contents )
def elem ( s : String ):Element=
new LineElement( s )
def elem ( u :Char, width :Int, height :Int):Element=
new UniformElement( u , width , height )
}
scala中的AnyRef是所有自定义类型的父类,类似于java中的Object,在AnyRef中包含以下方法。
eq:用来比较两个对象是否引用相等,若相等返回True。
ne:eq的反操作。
==:作用和equals相同,用来比较两个对象是否自然相等。
override
这个关键字在子类重写父类中有具体实现的方法的时候必须写override这个关键字,如果子类重写的方法在父类中是抽象方法,那么这个关键字是可选的。

常用特质trait
Ordered[A]:
任何需要使用">","<",">=","<="做比较的类都可以继承这个特质,继承这个特质之后,只需实现compare方法就能让自定义类直接使用上面的4个操作符进行比较。
例子:
class Rational(n:Int,d:Int) extends Ordered[Ratinal]{
//...
def compare(that:Rational) =
( this .number*that.denom)-( this .denom*that.number)
}

特质trait的堆叠改变
使用trait中super的动态绑定来实现特质的堆叠
trait的堆叠和普通情况有一个大区别就是trait要完成堆叠一定要继承一个class
第1步:定义一个抽象类
abstract class IntQueue {
def get ():Int
def put ( x :Int)
}
第2步:定义一个实现类
class BasicIntQueue extends IntQueue {
private val buf = new ArrayBuffer[Int]
def get = buf . remove ( 0 )
def put ( x :Int) { buf += x }
}
第3步:定义几个继承了抽象类IntQueue的特质:
trait Incrementing extends IntQueue {
abstract override def put ( x :Int){ super . put ( x + 1 )}
}
trait Filtering extends IntQueue {
abstract override def put ( x :Int){ if ( x >= 0 ) super . put ( x )}
}
第4步:使用特质的堆叠:
可以是:
val queue = ( new BasicIntQueue with Incrementing with Filtering )
queue . put (- 1 )
queue . put ( 0 )
queue . put ( 1 )
println ( queue . get ())
println ( queue . get ())
也可以是:
class MyQueue extends BasicIntQueue with Doubling

val queue = new MyQueue
queue . put (- 1 )
queue . put ( 0 )
queue . put ( 1 )
println ( queue . get ())
println ( queue . get ())
以上第4步的输出为:1,2
特质混入的次序是重要的,简单的说,越靠近右边的会越优先起作用,从右边开始,如果调用的那个方法带super的话,他调用其左侧的方法,以此类推。
特质堆叠顺序说明:

对于以上特质继承了类在说明一点注意,继承了以上Furry、FourLegged后的类默认继承了超类Animal所以由于java单继承的原因,就不能再继承别的类了。
混入对象的构造器的执行顺序:
  • 首先调用超类的构造器
  • 特质的构造器在超类构造器之后、类构造器之前执行
  • 特质从左到右被构造
  • 每个特质中,父特质先被构造
  • 如果多个特质共有一个父特质、而那个父特质已经被构造,则不会被再次构造
  • 所有的特质被构造完毕,子类被构造
以上面的Cat类为例:
class Cat extends Animal with Furry with FourLegged
lin(Cat)
=Cat>>lin(FourLegged)>>lin(Furry)>>lin(Animal)
=Cat>>(FourLegged>>lin(Haslegs))>>(Furry>>Animal)>>Animal
=Cat>>(FourLegged>>(Haslegs>>Animal))>>(Furry>>Animal)>>Animal
=Cat>>FourLegged>>Haslegs>>Furry>>Animal

这里的,>>意思是“串接并去掉重复项,右侧胜出”

trait
scala中的 trait定义特质类,这个关键字的作用类似于java中的interface,但是在scala中,特质类中除了抽象方法以外,还能有非抽象的方法,这就和java中的interface不同了。类可以通过extends或with关键字来实现特质,如果使用extends就只能继承一个,使用with就能继承多个。
trait中定义了字段,在类混入该trait的时候,这些字段不是被继承而是单纯的添加到子类当中
trait也有构造器,trait的构造器就是在trait中没有写在方法中的代码块。属于一个无参构造器
trait还引申出一个自身类型的概念:
当特质以如下代码开始定义时
this:类型 =>
它便只能被混入制定类型的子类
例1:
trait LoggedException{
this:Exception=>def log(){....)}
注意该特质并不扩展Exception类,而是有一个自身类型Exception,这意味着,它只能被混入Exception子类。
例2:
trait LoggedException{
this : {def getMessage():String}=>def log(){....)}
这个特质可以被混入任何拥有getMessage方法的类。

trait和class的区别:
trait可以当做一个特殊的类来使用,trait与class比较有以下两条区别:
1.class中的super关键字是静态绑定的,但是 tarit的super关键字是动态绑定的也trait的super只有在使用的时候才知道super调用哪个,正因为这样,所以才有上面说到的堆叠改变。
2.特质不能有任何类参数,即传递给主构造器的参数。

trait和java中interface的区别:
scala中的trait定义特质类,这个关键字的作用类似于java中的interface,但是在scala中,特质类中除了抽象方法以外,还能有非抽象的方法,这就和java中的interface不同了。类可以通过extends或with关键字来实现特质,如果使用extends就只能继承一个,使用with就能继承多个。

scala中的泛型一般来说是非协变的(或者说是严谨的),也就是说Queue[T]是泛型,S是T的子类型,但是Queue[S]不是Queue[T]的子类型,这种形式称之为严谨的。
但是如果将Queue[T]的定义改为Queue[+T]那么泛型Queue就是协变的。
如果Queue的定义为Queue[-T]那么泛型Queue就是逆变的

抽象的val只能用val重写不能用def重写,因为val限制了重写的次数。抽象的def可以用val或者def重写。以上两句就是要说明val比def严谨。






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值