17 抽象类(abstract class)与 特质(trait)
抽象类:
抽象类与Java相似,只是Java中没有属性的抽象,scala可以有属性的抽象;
特质:
可以把特质理解成Java中升级版的接口
在Java中接口不能声明没有值的属性和有实现的方法,而Scala可以声明没有值的属性和有实现的方法;
重写:
重写与Java相似,只是Java中没有重写属性的概念,而 scala 可以重写属性;
特质和抽象类的使用区别:
只能继承一个抽象类,但可以实现多个特质。这点和Java一样;
下面分别详细说明
17.1 抽象类
1)重写父类的非抽象成员(包括字段和方法)时,必须加上override 关键字;
package day03
abstract class Car {
// 定义普通属性
val name:String = "车"
// 定义抽象属性(属性不赋值)
val brand:String
// 定义普通方法
def description = {
println("这是抽象类里面的普通方法")
}
// 定义抽象方法(方法没有方法体)
def action():Unit
}
// 定义子类继承父类
class BYDCar extends Car{
// 子类重写父类的抽象成员,可加可不加 override
val brand: String = "比亚迪"
def action(): Unit = {
println("研发的刀片电池,使用更安全")
}
// 子类重写父类的非抽象成员,必须加override
override val name: String = "电车"
override def description: Unit = {
super.description
println(s"${brand} ${name}")
action()
}
}
object CarDemo{
def main(args: Array[String]): Unit = {
val car = new BYDCar
car.description
}
}
2)如果父类有构造器,则子类主构造器必须调用父类的主构造器或辅助构造器。
子类的辅助构造器,不能调用父类的构造器。
package day03
abstract class Car(val color:String) {
var price:Double = _
def this(color:String, price:Double) = {
this(color)
this.price = price
}
// 定义普通属性
val name:String = "车"
// 定义抽象属性(属性不赋值)
val brand:String
// 定义普通方法
def description = {
println("这是抽象类里面的普通方法")
}
// 定义抽象方法(方法没有方法体)
def action():Unit
}
// 定义子类继承父类
// 子类主构造器继承父类的主构造器
class BYDCar(color:String, types:String) extends Car(color:String){
// 子类重写父类的抽象成员,可加可不加 override
val brand: String = "比亚迪"
def action(): Unit = {
println("研发的刀片电池,使用更安全")
}
// 子类重写父类的非抽象成员,必须加override
override val name: String = "电车"
override def description: Unit = {
super.description
println(s"${brand} ${color} ${types} ${name}")
action()
}
}
// 继承父类的辅助构造器
class WULINGCar(color:String,price:Double, types:String) extends Car(color:String, price:Double){
// 子类重写父类的抽象成员,可加可不加 override
val brand: String = "五菱"
def action(): Unit = {
println("大众的选择,销量杠杠滴")
}
// 子类重写父类的非抽象成员,必须加override
override val name: String = "电车"
override def description: Unit = {
super.description
println(s"${brand} ${color} ${types} ${name}")
println(s"亲民价:${price}")
action()
}
}
object CarDemo{
def main(args: Array[String]): Unit = {
val car = new BYDCar("炫彩蓝", "秦DMI油电混")
car.description
println("-----------------")
val car2 = new WULINGCar("各种颜色", 28800,"宏光Mini")
car2.description
}
}
17.2 特质
定义特质需要用 trait 关键字;
特质可以包含抽象成员和非抽象成员,这与scala 的抽象类类似,包含抽象成员时,不需要abstract 关键字;
在Scala中,无论继承类还是继承Trait都是用extends关键字;
在重写特质的方法时,不需要给出override 关键字;
package day03
trait Fly {
// 定义普通属性
val name:String = "飞"
// 定义抽象属性
val maxFlyHigh:Int
// 定义普通方法
def description = {
println("这是特质里面的普通方法")
}
// 定义抽象方法
def action():Unit
}
class Bird extends Fly{
// 重写抽象成员
val maxFlyHigh: Int = 1000
def action(): Unit = {
println("鸟用翅膀飞")
}
// 重写非抽象成员
override val name: String = "火烈鸟"
override def description: Unit = {
super.description
println(s"${name}")
action()
println(s"最大飞行高度:${maxFlyHigh}")
}
}
object TraitTest{
def main(args: Array[String]): Unit = {
val bird = new Bird
bird.description
}
}
当不继承类直接实现一个特质,可以不用with直接用extends,实现多个特质的时候可以用多个with,但是必须先extends第一个
如: class T1 extends T2 with T3 with T4
package day03
trait Fly {
// 定义普通属性
val name:String = "飞"
// 定义抽象属性
val maxFlyHigh:Int
// 定义普通方法
def description = {
println("这是特质里面的普通方法")
}
// 定义抽象方法
def action():Unit
}
trait Run{
def run():Unit
}
class Bird extends Fly{
// 重写抽象成员
val maxFlyHigh: Int = 1000
def action(): Unit = {
println("鸟用翅膀飞")
}
// 重写非抽象成员
override val name: String = "火烈鸟"
override def description: Unit = {
super.description
println(s"${name}")
action()
println(s"最大飞行高度:${maxFlyHigh}")
}
}
// 实现多个特质用with
class AirPlane extends Fly with Run{
override val maxFlyHigh: Int = 10000
override def action(): Unit = {
println("飞机用翅膀飞")
}
override def run(): Unit = {
println("飞机用轱辘跑")
}
override def description: Unit = {
super.description
action()
run()
println(s"最大飞行高度:${maxFlyHigh}")
}
}
object TraitTest{
def main(args: Array[String]): Unit = {
val bird = new Bird
bird.description
println("------------------")
val plane = new AirPlane
plane.description
}
}
特质通过字段的初始化和其他特质体中的语句构成来实现构造的逻辑。
但特质不能 new 实例。
trait T1{
// 特质构造执行
val a:String = "aaa"
println(a)
def t1():Unit
}
trait T2{
// 特质构造执行
val b:String = "bbb"
println(b)
def t2():Unit
}
class T1Sub extends T1 with T2{
//本类构造执行
val c:String = "ccc"
println(c)
def t1():Unit={
println("do t1()")
}
def t2():Unit={
println("do t2()")
}
}
object T1SubTest{
def main(args: Array[String]): Unit = {
// 调用 new T1Sub 时,先执行T1的构造,再执行T2的构造,然后执行本类构造
val t = new T1Sub
t.t1()
t.t2()
}
}
//-----------运行结果-----------------
aaa
bbb
ccc
do t1()
do t2()
什么时候使用特质和抽象类?
使用角度
主次关系用抽象类,额外功能用特质,比如蜘蛛侠。
语法角度
1)优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。
2)如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行。