对象与伴生对象 #
一、单例对象 #
1.1 定义对象 #
使用 object 关键字定义单例对象:
scala
object Counter:
private var count = 0
def increment(): Int =
count += 1
count
def current: Int = count
Counter.increment()
Counter.increment()
println(Counter.current)
1.2 工具对象 #
scala
object MathUtils:
val PI = 3.141592653589793
def square(x: Double): Double = x * x
def cube(x: Double): Double = x * x * x
def factorial(n: Int): Int =
if n <= 1 then 1
else n * factorial(n - 1)
def isPrime(n: Int): Boolean =
if n < 2 then false
else !(2 to math.sqrt(n).toInt).exists(n % _ == 0)
println(MathUtils.PI)
println(MathUtils.square(5))
println(MathUtils.factorial(5))
println(MathUtils.isPrime(17))
1.3 配置对象 #
scala
object Config:
val host = "localhost"
val port = 8080
val timeout = 5000
def url: String = s"http://$host:$port"
println(Config.url)
二、伴生对象 #
2.1 定义伴生对象 #
与类同名且定义在同一文件中的对象:
scala
class Person(val name: String, val age: Int):
def greet(): String = s"Hello, I'm $name"
object Person:
def apply(name: String): Person = Person(name, 0)
def create(name: String, age: Int): Person = Person(name, age)
val p1 = Person("Alice")
val p2 = Person.create("Bob", 25)
2.2 访问私有成员 #
伴生对象可以访问类的私有成员:
scala
class Account private (val id: String, var balance: Double):
def deposit(amount: Double): Unit = balance += amount
object Account:
private var nextId = 0
def apply(initialBalance: Double): Account =
nextId += 1
new Account(s"ACC-$nextId", initialBalance)
val account = Account(1000.0)
println(account.id)
2.3 静态成员替代 #
scala
class Temperature(val celsius: Double):
def fahrenheit: Double = celsius * 9 / 5 + 32
def kelvin: Double = celsius + 273.15
object Temperature:
def fromFahrenheit(f: Double): Temperature = Temperature((f - 32) * 5 / 9)
def fromKelvin(k: Double): Temperature = Temperature(k - 273.15)
def absoluteZero: Temperature = Temperature(-273.15)
val t1 = Temperature(25)
val t2 = Temperature.fromFahrenheit(77)
val t3 = Temperature.fromKelvin(298.15)
val t4 = Temperature.absoluteZero
println(s"${t1.celsius}°C = ${t1.fahrenheit}°F")
三、apply 方法 #
3.1 工厂方法 #
scala
class Person(val name: String, val age: Int)
object Person:
def apply(name: String): Person = new Person(name, 0)
def apply(name: String, age: Int): Person = new Person(name, age)
val p1 = Person("Alice")
val p2 = Person("Bob", 25)
3.2 集合创建 #
scala
object MyList:
def apply[T](elements: T*): List[T] = elements.toList
val list = MyList(1, 2, 3, 4, 5)
println(list)
3.3 类型推断 #
scala
class Pair[A, B](val first: A, val second: B)
object Pair:
def apply[A, B](first: A, second: B): Pair[A, B] = new Pair(first, second)
val pair = Pair("hello", 42)
println(s"${pair.first}: ${pair.second}")
四、unapply 方法 #
4.1 提取器 #
用于模式匹配提取值:
scala
class Person(val name: String, val age: Int)
object Person:
def apply(name: String, age: Int): Person = new Person(name, age)
def unapply(person: Person): Option[(String, Int)] =
Some((person.name, person.age))
val person = Person("Alice", 25)
person match
case Person(name, age) => println(s"$name is $age years old")
4.2 布尔提取器 #
scala
object Even:
def unapply(n: Int): Boolean = n % 2 == 0
val number = 10
number match
case Even() => println("Even number")
case _ => println("Odd number")
4.3 序列提取器 #
scala
object FirstTwo:
def unapply(seq: Seq[?]): Option[(?, ?)] =
if seq.length >= 2 then Some((seq(0), seq(1)))
else None
val list = List(1, 2, 3, 4, 5)
list match
case FirstTwo(a, b) => println(s"First two: $a, $b")
case _ => println("Less than two elements")
五、枚举 #
5.1 使用 sealed trait #
scala
sealed trait Direction
case object North extends Direction
case object South extends Direction
case object East extends Direction
case object West extends Direction
def turn(direction: Direction): String = direction match
case North => "Going North"
case South => "Going South"
case East => "Going East"
case West => "Going West"
5.2 Scala 3 枚举 #
scala
enum Direction:
case North, South, East, West
def turn(direction: Direction): String = direction match
case Direction.North => "Going North"
case Direction.South => "Going South"
case Direction.East => "Going East"
case Direction.West => "Going West"
5.3 带参数的枚举 #
scala
enum Planet(mass: Double, radius: Double):
case Mercury extends Planet(3.303e+23, 2.4397e6)
case Venus extends Planet(4.869e+24, 6.0518e6)
case Earth extends Planet(5.976e+24, 6.37814e6)
case Mars extends Planet(6.421e+23, 3.3972e6)
def surfaceGravity: Double = 6.67300E-11 * mass / (radius * radius)
def surfaceWeight(otherMass: Double): Double = otherMass * surfaceGravity
println(Earth.surfaceGravity)
六、对象实战 #
6.1 工厂模式 #
scala
sealed trait Animal
case class Dog(name: String) extends Animal
case class Cat(name: String) extends Animal
object Animal:
def create(kind: String, name: String): Option[Animal] = kind match
case "dog" => Some(Dog(name))
case "cat" => Some(Cat(name))
case _ => None
val dog = Animal.create("dog", "Rex")
val cat = Animal.create("cat", "Whiskers")
6.2 构建器模式 #
scala
class Query private (
val table: String,
val columns: List[String],
val where: Option[String],
val limit: Option[Int]
)
object Query:
def builder(table: String): QueryBuilder = QueryBuilder(table)
class QueryBuilder(table: String):
private var columns = List("*")
private var where: Option[String] = None
private var limit: Option[Int] = None
def select(cols: String*): QueryBuilder =
columns = cols.toList
this
def where(condition: String): QueryBuilder =
where = Some(condition)
this
def limit(n: Int): QueryBuilder =
limit = Some(n)
this
def build: Query = Query(table, columns, where, limit)
val query = Query.builder("users")
.select("id", "name", "email")
.where("age > 18")
.limit(10)
.build
6.3 缓存对象 #
scala
object Cache:
private val store = scala.collection.mutable.Map.empty[String, Any]
def get[T](key: String): Option[T] =
store.get(key).map(_.asInstanceOf[T])
def put[T](key: String, value: T): Unit =
store.put(key, value)
def remove(key: String): Unit =
store.remove(key)
def clear(): Unit =
store.clear()
Cache.put("user", Map("name" -> "Alice"))
val user = Cache.get[Map[String, String]]("user")
6.4 类型类实例 #
scala
trait Show[A]:
def show(a: A): String
object Show:
def apply[A](implicit instance: Show[A]): Show[A] = instance
given Show[Int] with
def show(a: Int): String = a.toString
given Show[String] with
def show(a: String): String = a
given Show[Boolean] with
def show(a: Boolean): String = a.toString
def printShow[A](a: A)(using show: Show[A]): Unit =
println(show.show(a))
printShow(42)
printShow("hello")
printShow(true)
七、对象最佳实践 #
7.1 工具方法放在对象中 #
scala
object StringUtils:
def isBlank(s: String): Boolean = s == null || s.trim.isEmpty
def truncate(s: String, max: Int): String =
if s.length <= max then s else s.take(max) + "..."
7.2 使用伴生对象提供工厂方法 #
scala
class Connection private (val host: String, val port: Int)
object Connection:
def apply(host: String, port: Int): Connection = new Connection(host, port)
def localhost(port: Int = 8080): Connection = new Connection("localhost", port)
7.3 使用 sealed trait + case object 表示枚举 #
scala
sealed trait Status
case object Active extends Status
case object Inactive extends Status
case object Pending extends Status
八、总结 #
对象类型 #
| 类型 | 说明 |
|---|---|
| 单例对象 | 全局唯一实例 |
| 伴生对象 | 与类同名的对象 |
| case object | 单例样例对象 |
伴生对象用途 #
| 用途 | 方法 |
|---|---|
| 工厂方法 | apply |
| 提取器 | unapply |
| 静态成员 | val, def |
| 类型类实例 | given |
下一步,让我们学习 集合概述!
最后更新:2026-03-27