You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Scala单例对象Works.factory可序列化而Broken.factory不可?

为什么Works.factory可序列化,而Broken.factory不行?

这个问题的核心在于Scala单例对象、特质(trait)与Java序列化机制的交互细节,咱们一步步拆解:

1. 先看Works的正常情况

Works是一个顶层Scala单例对象,Scala会自动让所有顶层单例对象继承scala.Serializable,而且对单例对象的序列化有特殊优化:序列化时只保存一个标识,反序列化时直接返回全局唯一的单例实例,不会重新创建。

而Works里的factory是一个匿名Serializable类实例,它引用了外部的i方法。这个匿名类会持有对Works实例的引用——因为Works本身是可序列化的,所以整个factory实例在序列化时,JVM可以正常处理这个外部引用,自然就能顺利序列化。

2. 再看Broken的问题所在

Broken是继承自trait A的单例对象,这里的坑点出在trait A的定义上:

  • 虽然Broken作为单例对象默认是Serializable的,但trait A本身没有继承Serializable。
  • 在trait A中定义的factory匿名类,它引用的i是trait A中的方法,所以这个匿名类会持有一个静态类型为A的引用,指向Broken实例。
  • Java序列化机制是基于静态类型检查可序列化性的:当序列化Broken.factory时,JVM看到它持有一个A类型的引用,而A没有标记为Serializable,不管实际实例Broken是不是可序列化,都会直接抛出NotSerializableException。

验证与修复

如果把trait A修改为继承Serializable,问题就解决了:

trait A extends Serializable { def i = ??? val factory = new Serializable { def get = i } }

这时Broken.factory就能正常序列化——因为此时匿名类持有的A类型引用本身是可序列化的,JVM可以正常处理。

内容的提问来源于stack exchange,提问作者Kaarel Nummert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 08:54:08