我正在尝试使用内置的 Java 对象序列化库序列化一个 Scala 单例对象。
这里有一个序列化程序的例子:
object potato extends Serializable {
var dirt = 5
}
def main(args: Array[String]): Unit = {
val fileName = "potato.sav"
val potatoOutputStream = new ObjectOutputStream(new FileOutputStream(fileName))
potato.dirt = 12345
potatoOutputStream.writeObject(potato)
potatoOutputStream.close()
}
这是反序列化程序的示例:
object potato extends Serializable {
var dirt = 5
}
def main(args: Array[String]): Unit = {
val fileName = "potato.sav"
val potatoInputStream = new ObjectInputStream(new FileInputStream(fileName))
val p = potatoInputStream.readObject.asInstanceOf[potato.type]
println("potato dirt quantity " + p.dirt)
}
这会打印 5 而不是预期的 12345。 我在十六进制编辑器中查看了 potato.sav,数字 12345 甚至没有出现,它似乎是一个“scala.runtime.ModuleSerializationProxy”并且不包含任何字段数据。事实上,更改初始化程序或主函数中的任何数字都会导致逐字节相同的序列化文件:(
我有点理解为什么会发生这种情况,反序列化单例对象不能(或不应该)创建另一个实例,但我真的很想找到一种方法来实现这一点或类似的工作。我不需要使用内置的序列化库,但我需要一个不需要为每个单独的单例对象编写自定义序列化器/反序列化器的解决方案。
任何帮助将不胜感激。谢谢!
编辑: 我在这里使用对象是因为我想要某种类型的匿名子类的许多实例,每个实例都具有 DSL 的自定义逻辑。
不幸的是,使用对象似乎使它们不可序列化,因为它们是作为静态类实现的,java 不会序列化。结构类型也被淘汰了,因为在 scala 3 中你不能再访问可变状态作为某种新的和无法解释的限制,更不用说结构类型的性能问题了。
伴生对象的成员在 Java 中被建模为
static
成员。
来自docs:
When using a companion object from Java code, the members will be defined
in a companion class with a static modifier.
This is called static forwarding.
It occurs even if you haven’t defined a companion class yourself.
所以查找 Java 序列化如何与
static
字段一起工作。在 apache 反射实用程序的帮助下,最终编写了我自己的对象序列化例程。它不漂亮,但它有效。
def SerializeMembers(oos: ObjectOutputStream): Unit = {
val fields = FieldUtils.getAllFields(getClass)
for (f <- fields) {
val modifiers = f.getModifiers
val isNotFinal = (modifiers & Modifier.FINAL) == 0
if (isNotFinal) {
f.setAccessible(true)
oos.writeObject(f.get(this))
}
}
}
def DeserialzeMembers(ois: ObjectInputStream): Unit = {
val fields = FieldUtils.getAllFields(getClass)
for (f <- fields) {
val modifiers = f.getModifiers
val isNotFinal = (modifiers & Modifier.FINAL) == 0
if (isNotFinal) {
f.setAccessible(true)
val obj = ois.readObject()
f.set(this, obj)
}
}
}