scala的抽象类

50 阅读3分钟

一、抽象类的基础定义

抽象类(Abstract Class)是一种不能被直接实例化的类,用于定义通用的模板和规范。它可以包含:

  • 抽象成员:没有实现的方法(抽象方法)或没有初始值的字段(抽象字段)。
  • 具体成员:有实现的方法或有初始值的字段(普通成员)。

在 Scala 中,抽象类用 abstract 关键字修饰,核心规则:

  1. 抽象类不能直接 new 实例化。
  2. 子类继承抽象类时,必须实现所有未实现的抽象成员(除非子类也是抽象类)。
  3. 抽象类可以有构造器(主构造器 / 辅助构造器)。

二、基础示例:抽象类的定义与继承

// 定义抽象类:形状(包含抽象方法和具体方法)
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() // 输出:可以飞行
}

四、抽象类的典型使用场景

  1. 定义通用模板:当多个类有共同的属性和行为,但部分行为的实现不同时,用抽象类封装通用部分,抽象方法留待子类实现。
  2. 作为接口使用:类似 Java 的接口,但可以包含具体方法(比 Java 接口更灵活)。
  3. 配合多态:用抽象类引用指向子类对象,实现统一的调用逻辑。

总结

  1. 核心定义:Scala 抽象类用 abstract 修饰,不能实例化,可包含抽象成员(无实现)和具体成员(有实现)。
  2. 继承规则:子类必须实现抽象类的所有抽象成员(除非子类也是抽象类),实现时需加 override 关键字。
  3. 核心区别:抽象类支持带参构造器、单继承,适合定义核心业务模型;特质支持多继承、仅无参构造器,适合功能扩展。