1.3. 面向对象编程

Scala 是一门纯粹的面向对象语言——每个值都是对象,每个操作都是方法调用。

1.3.1. 类与对象

1.3.1.1. 定义类

class Person(name: String, age: Int):
  def greet(): String = s"Hi, I'm $name, $age years old."
  override def toString: String = s"Person($name, $age)"
val alice = Person("Alice", 30)
println(alice.greet())   // Hi, I'm Alice, 30 years old.

备注

Scala 3 使用轻量级的 class ... (params): 语法。 类主体直接用缩进开始,无需大括号。

1.3.1.2. 构造函数

Scala 的**主构造函数**直接写在类签名中:

// 主构造函数参数 name, age
class Person(val name: String, val age: Int):
  // 辅助构造函数
  def this(name: String) = this(name, 0)

参数可见性修饰符:

修饰符

效果

无修饰符

私有,不作为字段存储

val

公开的只读字段,生成 getter

var

公开的可读写字段,生成 getter + setter

private val

私有的只读字段

private var

私有的可读写字段

1.3.1.3. 访问修饰符

class AccessDemo:
  private val secret = "隐藏"              // 仅本类可见
  protected val family = "子类可见"         // 本类 + 子类
  val public = "公开"                       // 默认:公开
  private[this] val instanceOnly = "仅此实例"   // 实例级别私有

1.3.2. 特质(Trait)

特质类似 Java 的接口,但可以包含实现字段和方法:

trait HasName:
  def name: String           // 抽象方法
  def greet(): String =      // 具体实现方法
    s"Hello, I'm $name"

trait HasAge:
  def age: Int
  def isAdult: Boolean = age >= 18

// 混入多个特质
class Person(val name: String, val age: Int)
  extends HasName, HasAge:
  override def greet(): String = s"Hi, I'm $name"

小技巧

Scala 用 extends + , 代替 Java 的 implements 关键字。 特质中的 super 调用遵循线性化规则(类线性化)。

1.3.2.1. 特质与抽象类的选择

特性

特质 (trait)

抽象类 (abstract class)

多继承

支持(混入多个特质)

不支持(单继承)

构造函数参数

不支持

支持

与 Java 互操作

含实现的特质需 abstract class 桥接

自然兼容

推荐优先使用特质。

1.3.3. 样例类(Case Class)

样例类是 Scala 中的一等公民数据载体,编译器自动生成大量样板代码:

case class User(id: Long, name: String, email: String)

自动生成的内容:

// 1. 工厂方法(无需 new)
val u1 = User(1, "Alice", "alice@example.com")

// 2. 字段访问(val,不可变)
u1.name   // "Alice"

// 3. toString / hashCode / equals(值语义)
User(1, "Alice", "a@b") == User(1, "Alice", "a@b")   // true

// 4. copy 方法
val u2 = u1.copy(email = "new@example.com")

// 5. 模式匹配支持
u1 match
  case User(id, _, _) => println(s"用户 ID: $id")

警告

样例类的相等性基于**值**而非引用。如果需要引用语义,使用普通 class。

1.3.4. 单例对象与伴生对象

Scala 使用 object 关键字定义单例:

object Config:
  val AppName = "MyApp"
  val Version = "1.0"
  def load(): Unit = println("加载配置...")

// 直接调用
println(Config.AppName)
Config.load()

伴生对象:与类同名且在同一个文件中定义的 object:

class User(val name: String)
// 伴生对象,持有静态工厂方法
object User:
  def apply(name: String): User = new User(name)
  def anonymous: User = new User("guest")

// 使用工厂方法
val u1 = User("Alice")    // 等同于 User.apply("Alice")
val u2 = User.anonymous

1.3.5. 继承

// 基类
class Animal:
  def sound: String = "..."

// 子类,覆写方法需加 override
class Dog extends Animal:
  override def sound: String = "Woof!"

// 抽象类
abstract class Shape:
  def area: Double          // 抽象方法,无实现

class Circle(r: Double) extends Shape:
  override def area: Double = math.Pi * r * r

1.3.6. 密封类型(Sealed)

sealed 关键字限定类型只能在同一个文件中被继承, 使模式匹配穷举检查成为可能:

sealed trait TrafficLight
case object Red    extends TrafficLight
case object Yellow extends TrafficLight
case object Green  extends TrafficLight

def action(light: TrafficLight): String = light match
  case Red    => "停"
  case Yellow => "等待"
  case Green  => "行"
  // 编译器可验证匹配是否穷举

1.3.7. 枚举(Scala 3)

Scala 3 引入了原生枚举:

enum Color:
  case Red, Green, Blue

enum Suit(val symbol: String):
  case Hearts   extends Suit("♥")
  case Diamonds extends Suit("♦")
  case Clubs    extends Suit("♣")
  case Spades   extends Suit("♠")

println(Suit.Hearts.symbol)   // ♥