电脑知识铺
第二套高阶模板 · 更大气的阅读体验

Scala单例对象:理解与实际应用

发布时间:2025-12-22 04:10:24 阅读:144 次

在写Scala代码的时候,你可能会遇到这样的场景:想定义一个工具类,里面全是静态方法,像Java里的Math类那样,随时调用,不用new对象。Scala没有“static”关键字,那怎么办?这时候就得靠“单例对象”了。

什么是单例对象?

Scala里的单例对象是用object关键字定义的。它不依赖于类的实例,一启动就存在,全局唯一。你可以把它看作是一个“自带实例的类”,JVM里只有一份。

比如你要写个日志工具,不想每次用都new一次,直接定义成单例:

object Logger {
  def info(message: String): Unit = {
    println(s"[INFO] $message")
  }

  def error(message: String): Unit = {
    println(s"[ERROR] $message")
  }
}

调用的时候特别简单:

Logger.info("程序启动成功")

伴生对象:和类默契配合

如果一个object和一个class同名,并且在同一个文件里,它俩就是“伴生”。伴生对象可以访问类的私有成员,常用来放工厂方法或常量。

class Person private(val name: String)

object Person {
  def apply(name: String): Person = new Person(name)
}

这样创建Person就不用new了:

val p = Person("小明")  // 实际调用了Person.apply

这种写法在实际项目里很常见,尤其是集合类型,比如List(1,2,3),背后也是靠伴生对象的apply实现的。

单例对象的实际用途

除了工具类和工厂模式,单例还常用于配置管理。比如你的应用要读取端口配置,可以这样写:

object AppConfig {
  val defaultPort: Int = 8080
  val host: String = "localhost"
  
  def serverUrl: String = s"http://$host:$defaultPort"
}

anywhere都能通过AppConfig.serverUrl拿到地址,改配置也只改一处,省事又安全。

再比如,你想做简单的状态统计,记录请求次数:

object RequestCounter {
  private var count = 0

  def increment(): Unit = count += 1

  def getCount: Int = count
}

每次处理请求时调用RequestCounter.increment(),监控接口直接读取即可。

注意点

单例对象是延迟初始化的,第一次被访问时才创建。多线程下是线程安全的,Scala帮你搞定了。

但别滥用。如果对象里存了大量状态,又频繁修改,可能会影响性能或导致难以调试的问题。毕竟,全局唯一,改一处影响 everywhere。