0%

scala抽象类

Scala 抽象类:未完成的类与强制实现的契约

抽象类是面向对象编程中用于定义未完成逻辑的类,它包含抽象成员(抽象方法或抽象字段),需要子类实现才能被实例化。Scala 的抽象类机制与 Java 类似,但在语法和灵活性上有细微差异,尤其在抽象成员的定义和实现上更为简洁。本文将详细解析 Scala 抽象类的特性、定义方式及使用场景。

抽象类的基本定义

Scala 中抽象类通过 abstract 关键字声明,可包含抽象成员(无实现的方法或未初始化的字段)和具体成员(有实现的方法或已初始化的字段)。

语法格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
abstract class 类名 {
// 抽象字段(未初始化)
字段类型 字段名: 类型

// 抽象方法(无方法体)
def 方法名(参数列表): 返回值类型

// 具体字段(已初始化)
val/var 具体字段名: 类型 = 初始值

// 具体方法(有方法体)
def 具体方法名(参数列表): 返回值类型 = {
// 方法体
}
}

示例:定义抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 抽象类:Animal(动物)
abstract class Animal {
// 抽象字段:未初始化的名字和年龄
var name: String
val age: Int // val 抽象字段也需子类初始化

// 抽象方法:无实现的呼吸方法
def breath(): Unit

// 具体字段:所有动物共有的属性
val category: String = "生物"

// 具体方法:所有动物共有的行为
def eat(): Unit = {
println(s"$name 在吃东西")
}
}

核心特性

  1. 不能实例化:抽象类本身不完整,无法直接通过 new 实例化(与 Java 相同)。

    1
    // val animal = new Animal()  // 编译错误:抽象类不能实例化
  2. 必须被继承:抽象类的抽象成员需由子类实现,子类若未完全实现所有抽象成员,则自身也必须声明为抽象类。

抽象成员的实现(子类责任)

子类继承抽象类时,必须实现所有抽象字段和抽象方法,否则子类需声明为 abstract。与 Java 不同,Scala 中实现抽象成员无需 override 关键字(编译器自动识别)。

实现抽象字段和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 子类:Dog(继承自Animal)
class Dog extends Animal {
// 实现抽象字段(var 可修改,val 不可修改)
var name: String = "小狗" // 实现 var 抽象字段
val age: Int = 2 // 实现 val 抽象字段

// 实现抽象方法
def breath(): Unit = {
println(s"$name 用肺呼吸")
}

// 重写具体方法(需用 override)
override def eat(): Unit = {
println(s"$name 啃骨头")
}
}

// 测试
val dog = new Dog()
dog.breath() // 输出:小狗 用肺呼吸
dog.eat() // 输出:小狗 啃骨头
println(dog.category) // 输出:生物(继承的具体字段)

部分实现(抽象子类)

若子类仅实现部分抽象成员,需声明为抽象类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 抽象子类:Bird(未完全实现Animal的抽象成员)
abstract class Bird extends Animal {
// 仅实现部分抽象字段
var name: String = "小鸟"

// 未实现 age 字段和 breath 方法,因此必须声明为 abstract
}

// 具体子类:Sparrow(继承自Bird,完成所有实现)
class Sparrow extends Bird {
val age: Int = 1 // 实现从Animal继承的age字段

def breath(): Unit = { // 实现从Animal继承的breath方法
println(s"$name 用肺呼吸(辅助气囊)")
}
}

抽象类的关键规则

1. 抽象成员的访问修饰符

  • 抽象字段和方法

    不能用 privatefinal 修饰

    (需被子类实现,私有或不可重写会导致矛盾)。

1
2
3
4
abstract class Invalid {
// private var x: Int // 编译错误:抽象字段不能是private
// final def f(): Unit // 编译错误:抽象方法不能是final
}

2. 抽象类与具体类的区别

特性 抽象类(Abstract Class) 具体类(Concrete Class)
实例化 不能直接实例化 可直接实例化
成员完整性 可包含抽象成员(未实现) 所有成员必须有实现(字段初始化,方法有体)
继承目的 定义接口规范,强制子类实现抽象成员 提供完整功能,可直接使用或被继承扩展

3. 抽象类与特质(Trait)的区别

Scala 中抽象类与特质(Trait)都可包含抽象成员,但存在核心差异:

  • 继承限制:抽象类支持单继承(一个类只能继承一个抽象类),特质支持多混入(一个类可混入多个特质)。
  • 构造器:抽象类可定义带参数的构造器,特质不能有参数化构造器。
  • 使用场景:抽象类适合作为 “is-a” 关系的基类(如 AnimalDog),特质适合定义 “has-a” 功能(如 FlyableSwimmable)。

抽象类的应用场景

1. 定义基类规范

抽象类适合作为一组相关类的基类,定义共同的抽象接口,强制子类实现核心功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 抽象基类:Shape(图形)
abstract class Shape {
def area(): Double // 抽象方法:计算面积
def perimeter(): Double // 抽象方法:计算周长
}

// 子类:Circle(圆形)
class Circle(radius: Double) extends Shape {
def area(): Double = Math.PI * radius * radius
def perimeter(): Double = 2 * Math.PI * radius
}

// 子类:Rectangle(矩形)
class Rectangle(width: Double, height: Double) extends Shape {
def area(): Double = width * height
def perimeter(): Double = 2 * (width + height)
}

2. 模板方法模式

抽象类可定义 “模板方法”(具体方法),其中调用抽象方法,由子类实现细节,实现代码复用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 抽象类:Game(游戏)
abstract class Game {
// 模板方法:固定的游戏流程
def play(): Unit = {
start()
playLogic() // 调用抽象方法(子类实现)
end()
}

// 具体方法:固定步骤
def start(): Unit = println("游戏开始")
def end(): Unit = println("游戏结束")

// 抽象方法:子类实现的游戏逻辑
def playLogic(): Unit
}

// 子类:Chess( chess 游戏)
class Chess extends Game {
def playLogic(): Unit = {
println(" chess 游戏:落子、吃子、将军...")
}
}

// 测试
val chess = new Chess()
chess.play()
// 输出:
// 游戏开始
// chess 游戏:落子、吃子、将军...
// 游戏结束

最佳实践

  1. 适度使用抽象类:抽象类适合定义层次化的基类,若需多继承功能,优先使用特质(Trait)。
  2. 抽象成员最小化:抽象类应只包含必要的抽象成员,具体成员尽量提供默认实现,减少子类负担。
  3. 避免深层继承:抽象类的继承层次不宜过深(建议不超过 3 层),否则会导致代码复杂度上升。
  4. 构造器参数合理设计:抽象类可定义带参数的主构造器,便于子类初始化时传递必要信息。
1
2
3
4
5
6
7
8
9
10
// 带参数的抽象类
abstract class Person(name: String) {
def introduce(): Unit // 抽象方法
}

class Student(name: String, id: String) extends Person(name) {
def introduce(): Unit = {
println(s"我是学生 $name,学号 $id")
}
}

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10