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单继承的原因,就不能再继承别的类了。 混入对象的构造器的执行顺序:
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严谨。