scala可以在子类的构造器中重写父类的属性,例如:
abstractclassElement{
defcontents:Array[String]
valheight:Int
=contents.length
valwidth:Int
=if(height==0)0elsecontents(0).length
}
子类:
classUniformElement(u:Char,overridevalwidth:Int,overridevalheight:Int)extendsElement{
privatevalline=u.toString()*width
defcontents
=Array.fill(height)(line)
}
可以看到父类的height、width在子类的构造器中,以参数的形式被重写了。
聚义例子:
importElement.elem
abstractclassElement{
defcontents:Array[String]
defheight:Int
=contents.length
defwidth:Int
=if(height==0)0elsecontents(0).length
defabove(that:Element):Element=
elem(this.contents++that.contents)
defbeside(that:Element):Element={
elem(for((line1,line2)
<-this.contentszipthat.contents)yieldline1+line2)
}
overridedeftoString=contentsmkString"/n"
}
objectElement{
privateclassArrayElement(valcontents:Array[String])extendsElement
privateclassLineElement(s:String)extendsElement{
valcontents=Array(s)
overridedefwidth=s.length
overridedefheight=1
}
privateclassUniformElement(u:Char,overridevalwidth:Int,overridevalheight:Int)extendsElement{
privatevalline=u.toString()*width
defcontents=Array.fill(height)(line)
}
defelem(contents:Array[String]):Element=
newArrayElement(contents)
defelem(s:String):Element=
newLineElement(s)
defelem(u:Char,width:Int,height:Int):Element=
newUniformElement(u,width,height)
}
|
scala中的AnyRef是所有自定义类型的父类,类似于java中的Object,在AnyRef中包含以下方法。 eq:用来比较两个对象是否引用相等,若相等返回True。 ne:eq的反操作。 ==:作用和equals相同,用来比较两个对象是否自然相等。 |
override 这个关键字在子类重写父类中有具体实现的方法的时候必须写override这个关键字,如果子类重写的方法在父类中是抽象方法,那么这个关键字是可选的。 |
常用特质trait
Ordered[A]: 任何需要使用">","<",">=","<="做比较的类都可以继承这个特质,继承这个特质之后,只需实现compare方法就能让自定义类直接使用上面的4个操作符进行比较。 例子: classRational(n:Int,d:Int)extendsOrdered[Ratinal]{
//...
defcompare(that:Rational)
=
(this.number*that.denom)-(this.denom*that.number)
}
|
特质trait的堆叠改变
使用trait中super的动态绑定来实现特质的堆叠
trait的堆叠和普通情况有一个大区别就是trait要完成堆叠一定要继承一个class
第1步:定义一个抽象类 abstractclassIntQueue
{
defget():Int
defput(x:Int)
}
第2步:定义一个实现类classBasicIntQueueextendsIntQueue
{
privatevalbuf=newArrayBuffer[Int]
defget=buf.remove(0)
defput(x:Int)
{buf+=x}
}
第3步:定义几个继承了抽象类IntQueue的特质:traitIncrementingextendsIntQueue
{
abstractoverridedefput(x:Int){super.put(x+1)}
}
traitFilteringextendsIntQueue
{
abstractoverridedefput(x:Int){if(x>=0)super.put(x)}
}
第4步:使用特质的堆叠:可以是: valqueue=
(newBasicIntQueuewithIncrementingwithFiltering)
queue.put(-1)
queue.put(0)
queue.put(1)
println(queue.get())
println(queue.get())
也可以是:classMyQueueextendsBasicIntQueuewithDoubling
valqueue=newMyQueue
queue.put(-1)
queue.put(0)
queue.put(1)
println(queue.get())
println(queue.get())
以上第4步的输出为:1,2特质混入的次序是重要的,简单的说,越靠近右边的会越优先起作用,从右边开始,如果调用的那个方法带super的话,他调用其左侧的方法,以此类推。 特质堆叠顺序说明: 对于以上特质继承了类在说明一点注意,继承了以上Furry、FourLegged后的类默认继承了超类Animal所以由于java单继承的原因,就不能再继承别的类了。 混入对象的构造器的执行顺序:
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严谨。