一、抽象类的基础定义
抽象类(Abstract Class)是一种不能被直接实例化的类,用于定义通用的模板和规范。它可以包含:
- 抽象成员:没有实现的方法(抽象方法)或没有初始值的字段(抽象字段)。
- 具体成员:有实现的方法或有初始值的字段(普通成员)。
在 Scala 中,抽象类用 abstract 关键字修饰,核心规则:
- 抽象类不能直接
new实例化。 - 子类继承抽象类时,必须实现所有未实现的抽象成员(除非子类也是抽象类)。
- 抽象类可以有构造器(主构造器 / 辅助构造器)。
二、基础示例:抽象类的定义与继承
// 定义抽象类:形状(包含抽象方法和具体方法)
abstract class Shape {
// 抽象字段:颜色(无初始值,子类必须实现)
val color: String
// 抽象方法:计算面积(无实现,子类必须实现)
def area(): Double
// 具体方法:通用描述(有实现,子类可直接复用)
def describe(): String = s"这是一个${color}的形状,面积为${area()}"
}
// 子类1:圆形(实现抽象类的所有抽象成员)
class Circle(val radius: Double) extends Shape {
// 实现抽象字段 color
override val color: String = "红色"
// 实现抽象方法 area
override def area(): Double = Math.PI * radius * radius
}
// 子类2:矩形(实现抽象类的所有抽象成员)
class Rectangle(val width: Double, val height: Double) extends Shape {
// 实现抽象字段 color
override val color: String = "蓝色"
// 实现抽象方法 area
override def area(): Double = width * height
}
// 测试代码
object AbstractClassDemo extends App {
// 不能直接 new Shape() // 编译报错:抽象类无法实例化
// 实例化子类
val circle = new Circle(2.0)
println(circle.describe()) // 输出:这是一个红色的形状,面积为12.566370614359172
val rectangle = new Rectangle(3.0, 4.0)
println(rectangle.describe()) // 输出:这是一个蓝色的形状,面积为12.0
// 多态:抽象类引用指向子类对象
val shape1: Shape = new Circle(1.0)
val shape2: Shape = new Rectangle(2.0, 3.0)
println(shape1.area()) // 输出:3.141592653589793
}
三、抽象类的核心特性详解
1. 抽象成员的规则
- 抽象方法:只有方法签名,没有方法体(无需加
abstract关键字,Scala 会自动识别)。 - 抽象字段:只有字段声明,没有初始值(val/var 都可以)。
- 子类实现抽象成员时,必须加
override关键字(Scala 强制要求,避免误写)。
2. 抽象类的构造器
抽象类可以有主构造器和辅助构造器,子类继承时需要遵循构造器传递规则:
// 带参数的抽象类
abstract class Animal(val name: String) {
// 抽象方法
def makeSound(): String
}
// 子类继承时,需传递构造器参数
class Dog(name: String) extends Animal(name) {
override def makeSound(): String = s"$name 汪汪叫"
}
object AnimalDemo extends App {
val dog = new Dog("旺财")
println(dog.makeSound()) // 输出:旺财 汪汪叫
}
3. 抽象类的继承限制
-
一个子类只能继承一个抽象类(Scala 遵循单继承原则)。
-
若子类不想实现抽象成员,子类也必须声明为
abstract:abstract class Shape { def area(): Double } // 子类也是抽象类,无需实现 area 方法 abstract class Polygon extends Shape { def sideCount(): Int // 新增抽象方法 } // 最终子类必须实现所有抽象方法(Shape + Polygon) class Square(val side: Double) extends Polygon { override def area(): Double = side * side override def sideCount(): Int = 4 }
4. 抽象类 vs 特质(trait)
这是 Scala 新手容易混淆的点,核心区别:
| 特性 | 抽象类 (abstract class) | 特质 (trait) |
|---|---|---|
| 继承数量 | 只能单继承 | 可以多继承(with 关键字) |
| 构造器 | 可以有带参数的构造器 | 只能有无参构造器 |
| 使用场景 | 定义核心业务模型 | 定义行为 / 功能扩展 |
示例:抽象类 + 特质 组合使用
// 抽象类:核心模型
abstract class Vehicle(val brand: String) {
def run(): Unit // 抽象方法
}
// 特质:功能扩展
trait Flyable {
def fly(): Unit = println("可以飞行")
}
// 子类:继承抽象类 + 混入特质
class FlyingCar(brand: String) extends Vehicle(brand) with Flyable {
override def run(): Unit = println(s"$brand 能跑")
}
object Demo extends App {
val car = new FlyingCar("未来汽车")
car.run() // 输出:未来汽车 能跑
car.fly() // 输出:可以飞行
}
四、抽象类的典型使用场景
- 定义通用模板:当多个类有共同的属性和行为,但部分行为的实现不同时,用抽象类封装通用部分,抽象方法留待子类实现。
- 作为接口使用:类似 Java 的接口,但可以包含具体方法(比 Java 接口更灵活)。
- 配合多态:用抽象类引用指向子类对象,实现统一的调用逻辑。
总结
- 核心定义:Scala 抽象类用
abstract修饰,不能实例化,可包含抽象成员(无实现)和具体成员(有实现)。 - 继承规则:子类必须实现抽象类的所有抽象成员(除非子类也是抽象类),实现时需加
override关键字。 - 核心区别:抽象类支持带参构造器、单继承,适合定义核心业务模型;特质支持多继承、仅无参构造器,适合功能扩展。