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类对象时,就会按照前面的构造器执行顺序来执行构造。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容