Scala的抽象类使用关键字abstract定义,具有以下特征:
· 抽象类不能被实例化。
· 抽象类中可以定义抽象字段(没有初始化的字段)和抽象方法(没有被实现的方法),也可以定义被初始化的字段和被实现的方法。
· 若某个子类继承了一个抽象类,则必须实现抽象类中的抽象字段和抽象方法,且实现的过程中可以添加override关键字,也可以省略。若重写了抽象类中已经实现的方法,则必须添加override关键字。
例如,定义一个抽象类Person,代码如下:
//定义抽象类Person abstract class Person { //抽象字段 var name:String var age:Int //普通字段 var address:String="北京" //抽象方法 def speak() //普通方法 def eat():Unit={ println("吃东西") } }
定义一个普通类Teacher,并继承抽象类Person,实现Person中的抽象字段和抽象方法,并重写方法eat(),代码如下:
//继承了抽象类Person class Teacher extends Person{ //实现抽象字段 var name: String = "王丽" var age: Int = 28 //实现抽象方法 def speak(): Unit = { println("姓名:"+this.name) println("年龄:"+this.age) println("地址:"+this.address)//继承而来 println("擅长讲课") } //重写非抽象方法,必须添加override关键字 override def eat():Unit={ println("爱吃中餐") } }
定义一个测试对象,调用Teacher类中的方法,代码如下:
object AppTest{ def main(args: Array[String]): Unit = { val teacher=new Teacher() //调用方法 teacher.speak() teacher.eat() } } 输出结果如下: 姓名:王丽 年龄:28 地址:北京 擅长讲课 爱吃中餐
需要注意的是,上述Teacher类中speak()方法的地址字段(address)是从父类(抽象类Person)中继承而来的。由于该字段在Person中有初始化值,不是抽象字段,若需要在Teacher类中修改该字段的值,则可以在Teacher类的构造函数或其他方法中使用this.address对其重新赋值。例如,将地址改为“上海”,可以使用以下代码:
this.address="上海"
由于Person类中的address字段使用var修饰,而Scala不允许对抽象类中var修饰的非抽象字段进行重写,因此在Teacher类中对address字段进行重写将报编译错误,除非该字段在Person类中的声明是不可变的,即使用val修饰。
Scala特质使用关键字trait定义,类似Java 8中使用interface定义的接口。特质除了有Java接口的功能外,还有一些特殊的功能。下面分别进行讲解。
Scala特质中,字段和方法的定义与Scala抽象类一样,可以定义抽象字段和抽象方法、非抽象字段和非抽象方法。例如以下代码定义了一个特质Pet:
//定义特质(宠物) trait Pet { //抽象字段 var name:String var age:Int //抽象方法 def run //非抽象方法 def eat: Unit ={ println("吃东西") } }
类可以使用关键字extends实现特质,但必须实现特质中未实现的字段和方法(抽象字段和抽象方法),这一点与继承抽象类是一致的。例如以下代码定义了一个普通类Cat,实现了上述特质Pet:
//定义类(猫)继承特质(宠物) class Cat extends Pet{ //实现抽象字段 var name:String="john" var age:Int=3 //实现抽象方法 def run: Unit = { println("会跑") } //重写非抽象方法 override def eat: Unit ={ println("吃鱼") } }
如果需要实现的特质不止一个,那么可以通过with关键字添加额外特质,但位于最左侧的特质必须使用extends关键字。例如,类Dog同时实现了特质Pet、Animal和Runable,代码如下:
trait Animal{ } trait Runable{ } //类Dog实现了3个特质 class Dog extends Pet with Animal with Runable{ //省略 }
在类实例化的时候,也可以通过with关键字混入多个特质,从而使用特质中的方法。例如以下代码定义了两个特质Runable、Flyable和一个类Bird:
//定义两个特质 trait Runable{ def run=println("会跑") } trait Flyable{ def fly=println("会飞") } //定义一个类 class Bird{ }
在类Bird实例化时混入特质Runable和Flyable,代码如下:
val bird=new Bird() with Runable with Flyable bird.run //输出结果“会跑” bird.fly //输出结果“会飞”