scala 类的继承

15 阅读3分钟

一、Scala 类继承的基础规则

Scala 中的类继承和 Java 有相似之处,但也有自己的特点:

  1. 默认不可继承:Scala 中普通类默认是 final 的(不可继承),必须用 class 类名 前加 open 关键字才能被继承(Scala 3);Scala 2 中需要显式去掉 final 或用 sealed 限制继承范围。
  2. 继承语法:使用 extends 关键字,格式为 class 子类 extends 父类
  3. 构造器调用:子类构造器会优先调用父类的主构造器,若要调用父类辅助构造器,需在子类构造器中显式处理。
  4. 方法重写:重写父类方法必须用 override 关键字(强制要求,避免误写)。

二、基础示例:简单类的继承

1. Scala 3 版本(推荐)

// 父类:用 open 标记可继承
open class Person(val name: String, val age: Int) {
  // 父类方法
  def introduce(): String = s"我叫$name,今年$age 岁"
  
  // 辅助构造器
  def this(name: String) = this(name, 0)
}

// 子类:继承 Person
class Student(name: String, age: Int, val studentId: String) extends Person(name, age) {
  // 重写父类方法,必须加 override
  override def introduce(): String = s"我叫$name,今年$age 岁,学号是$studentId"
  
  // 子类独有方法
  def study(): Unit = println(s"$name 正在学习")
}

// 测试代码
object InheritDemo extends App {
  val student = new Student("张三", 18, "2024001")
  println(student.introduce()) // 输出:我叫张三,今年18岁,学号是2024001
  student.study() // 输出:张三正在学习
  
  // 父类引用指向子类对象(多态)
  val person: Person = new Student("李四", 19, "2024002")
  println(person.introduce()) // 输出:我叫李四,今年19岁,学号是2024002
}

2. Scala 2 版本(无 open 关键字)

// Scala 2 中无需 open,默认可继承(除非加 final)
class Person(val name: String, val age: Int) {
  def introduce(): String = s"我叫$name,今年$age 岁"
  def this(name: String) = this(name, 0)
}

class Student(name: String, age: Int, val studentId: String) extends Person(name, age) {
  override def introduce(): String = s"我叫$name,今年$age 岁,学号是$studentId"
  def study(): Unit = println(s"$name 正在学习")
}

object InheritDemo extends App {
  val student = new Student("张三", 18, "2024001")
  println(student.introduce())
}

三、关键知识点详解

1. 构造器的继承规则

  • 子类主构造器的参数会自动传递给父类主构造器(如 extends Person(name, age))。

  • 若父类没有无参主构造器,子类必须显式调用父类的有参构造器,否则编译报错。

  • 示例:父类只有有参构造器时,子类的写法

    open class Person(name: String) { // 父类主构造器有参
      val fullName = name
    }
    
    // 子类必须显式传参给父类构造器
    class Student(name: String, id: String) extends Person(name) {
      val studentId = id
    }
    

2. 方法重写

  • 必须加 override 关键字(Scala 强制要求,Java 是可选)。

  • 若父类方法是 final,子类无法重写。

  • 可以重写 val 字段(本质是重写字段的 getter 方法):

    open class Person {
      val info: String = "父类信息"
    }
    
    class Student extends Person {
      override val info: String = "子类信息" // 重写字段
    }
    

3. 抽象类的继承

Scala 中抽象类用 abstract 修饰,包含抽象方法 / 字段(无实现),子类必须实现抽象成员:

// 抽象父类
abstract class Shape {
  // 抽象方法(无实现)
  def area(): Double
  // 抽象字段(无初始值)
  val color: String
}

// 子类实现抽象成员
class Circle(val radius: Double) extends Shape {
  override def area(): Double = Math.PI * radius * radius
  override val color: String = "red"
}

object ShapeDemo extends App {
  val circle = new Circle(2.0)
  println(circle.area()) // 输出:12.566370614359172
  println(circle.color) // 输出:red
}

4. 单继承限制

和 Java 一样,Scala 类只能单继承(一个子类只能有一个直接父类),但可以通过 trait(特质)实现类似多继承的效果。

四、总结

  1. 核心语法:Scala 3 中父类需加 open 才能被继承,子类用 extends 关键字,重写方法 / 字段必须加 override
  2. 构造器规则:子类构造器必须显式调用父类构造器(若父类无无参构造器),参数通过 extends 父类(参数) 传递。
  3. 关键特性:Scala 支持抽象类继承、字段重写,且强制 override 关键字,避免误重写,同时遵循单继承原则(可结合 trait 补充多继承能力)。