Scala编程基础24:Scala特征
Scala Trait(特征)相当于Java中的接口,实际上它比接口的功能还要强大。与接口不同的是,Trait可以定义属性和方法的实现。一般情况下,Scala的类只能继承单一父类,但是可以继承多个Trail。Trait定义方式与类的定义类似,但是使用trait关键字,
1.定义Trait
下面的例子演示了Trait的定义:
trait Equal {
def isEqual(x:Any):Boolean;
def isNotEuqal(x:Any):Boolean=!isEqual(x);
}
以上Trait(特征)由两个方法组成:isEqual和isNotEuqal。isEqual方法没有定义方法的实现,isNotEqual定义了方法的实现。子类继承Trait可以实现未实现的方法。这一点Scala Trait更像Java的抽象类(抽象类:含有抽象方法的类;接口:全部方法都是抽象方法)。
2.使用Trait
下面的例子演示了trait的使用:
trait Equal {
def isEqual(obj:Any):Boolean;
def func1()={
"from trait Equal";
}
}
trait NotEqual {
def isNotEqual(obj:Any):Boolean;
def func2()={
"from trait NotEqual";
}
}
class Point(xc:Int,yc:Int) extends Equal with NotEqual {
var x:Int = xc;
var y:Int = yc;
def isEqual(obj:Any) = {
obj.isInstanceOf[Point] &&
obj.asInstanceOf[Point].x == x &&
obj.asInstanceOf[Point].y == y;
}
def isNotEqual(obj:Any) = {
!(obj.isInstanceOf[Point] &&
obj.asInstanceOf[Point].x == x &&
obj.asInstanceOf[Point].y == y);
}
override def func2() = {
"from class Point";
}
}
object Test1 {
def main(args:Array[String]) {
val p1 = new Point(2,3);
val p2 = new Point(2,4);
println("p1("+p1.x+","+p1.y+")");
println("p2("+p2.x+","+p2.y+")");
println("p1.isEqual(p1) = "+p1.isEqual(p1));
println("p1.isEqual(p2) = "+p1.isEqual(p2));
println("p2.isNotEqual(p1) = "+p2.isNotEqual(p1));
println("p2.isNotEqual(p2) = "+p2.isNotEqual(p2));
println("p1.func1 "+p1.func1);
println("p1.func2 "+p1.func2);
}
}
编译并执行上述代码,输出结果如下:
E:\Test>scalac Test1.scala
E:\Test>scala Test1
p1(2,3)
p2(2,4)
p1.isEqual(p1) = true
p1.isEqual(p2) = false
p2.isNotEqual(p1) = true
p2.isNotEqual(p2) = false
p1.func1 from trait Equal
p1.func2 from class Point
根据上述代码,需要注意以下几点:
- Scala的类继承Trait使用extends关键字,多个Trait之间使用with连接;
- Trait中的抽象方法(没有实体)必须要重写,如isEqual和isNotEqual;
- Trait中的非抽象方法(有实体)可以不重写,如func1;但是如果重写,需要使用override关键字修饰,如func2;
3.Trait构造顺序
Trait也可以有构造器,由字段的初始化和其他语句构成。这些语句在继承该Trait的对象构造时都会被执行。
构造器的执行顺序如下:
- 调用超类的构造器
- 调用特征的构造器
- 调用子类的构造器
其中特征的构造需要注意以下几点:
- 特征由左到右被依次构造
- 每个特征中,父特征先被构造
- 如果多个特征共有一个父特征,父特征不会被重复构造
- 所有的特征被构造完毕,子类才被构造
下面的例子演示了各种构造器的执行顺序:
trait duobianxing {
println("construct trait duobianxing");
}
trait lingxing extends duobianxing {
println("construct trait lingxing");
}
trait juxing extends duobianxing {
println("construct trait juxing");
}
trait zhengfangxing extends lingxing with juxing {
println("construct trait zhengfangxing");
}
class tuxing {
println("construct class tuxing");
}
class mySquare extends tuxing with zhengfangxing {
println("construct class mySquare");
}
object Test2 {
def main(args:Array[String]) {
var square:mySquare = new mySquare();
println("this is main method");
}
}
编译并执行上述代码,输出结果如下:
E:\Test>scalac Test2.scala
E:\Test>scala Test2
construct class tuxing
construct trait duobianxing
construct trait lingxing
construct trait juxing
construct trait zhengfangxing
construct class mySquare
this is main method
上面的例子中:
- 定义特征:多边形duobianxing
- 定义特征:菱形lingxing和矩形juxing,继承自:多边形duobianxing
- 定义特征:正方形zhengfangxing,继承自:菱形lingxing和矩形juxing
- 定义类:图形tuxing
- 定义子类:mySquare,继承自:图形tuxing和正方形zhengfangxing
- 当实例化mySquare类对象时,就会按照前面的构造器执行顺序来执行构造。