惰性字段的序列化是如何工作的?
How does serialization of lazy fields work?
当出于某些原因需要推迟对值的评估时,我知道惰性字段的好处。我想知道惰性字段在序列化方面的行为是什么。
考虑以下 class。
class MyClass {
lazy val myLazyVal = {...}
...
}
问题:
- 如果 MyClass 的实例被序列化,惰性字段是否也被序列化?
- 如果字段在序列化之前是否被访问过,序列化的行为会改变吗?我的意思是,如果我不引起字段的评估,它是否被认为是 null ?
- 序列化机制是否会引发惰性字段的隐式求值?
- 有没有一种简单的方法可以避免变量的序列化并在反序列化后延迟重新计算一次值?这应该独立于现场评估而发生。
答案
- 是的,如果字段已经初始化,如果没有,您可以将其视为一种方法。值未计算 -> 未序列化,但在反序列化后可用。
- 如果你没有接触字段,它几乎被序列化,因为它是一个简单的'def'方法,你不需要它的类型本身是可序列化的,它会在反序列化后重新计算
- 没有
- 您可以在我的代码示例中的 lazy val 定义之前添加 @transient,据我所知,它将完全按照您的要求进行操作
代码证明
object LazySerializationTest extends App {
def serialize(obj: Any): Array[Byte] = {
val bytes = new ByteArrayOutputStream()
val out = new ObjectOutputStream(bytes)
out.writeObject(obj)
out.close()
bytes.toByteArray
}
def deSerialise(bytes: Array[Byte]): MyClass = {
new ObjectInputStream(new ByteArrayInputStream(bytes)).
readObject().asInstanceOf[MyClass]
}
def test(obj: MyClass): Unit = {
val bytes = serialize(obj)
val fromBytes = deSerialise(bytes)
println(s"Original cnt = ${obj.x.cnt}")
println(s"De Serialized cnt = ${fromBytes.x.cnt}")
}
object X {
val cnt = new AtomicInteger()
}
class X {
// Not Serializable
val cnt = X.cnt.incrementAndGet
println(s"Create instance of X #$cnt")
}
class MyClass extends Serializable {
lazy val x = new X
}
// Not initialized
val mc1 = new MyClass
test(mc1)
// Force lazy evaluation
val mc2 = new MyClass
mc2.x
test(mc2) // Failed with NotSerializableException
}
当出于某些原因需要推迟对值的评估时,我知道惰性字段的好处。我想知道惰性字段在序列化方面的行为是什么。
考虑以下 class。
class MyClass {
lazy val myLazyVal = {...}
...
}
问题:
- 如果 MyClass 的实例被序列化,惰性字段是否也被序列化?
- 如果字段在序列化之前是否被访问过,序列化的行为会改变吗?我的意思是,如果我不引起字段的评估,它是否被认为是 null ?
- 序列化机制是否会引发惰性字段的隐式求值?
- 有没有一种简单的方法可以避免变量的序列化并在反序列化后延迟重新计算一次值?这应该独立于现场评估而发生。
答案
- 是的,如果字段已经初始化,如果没有,您可以将其视为一种方法。值未计算 -> 未序列化,但在反序列化后可用。
- 如果你没有接触字段,它几乎被序列化,因为它是一个简单的'def'方法,你不需要它的类型本身是可序列化的,它会在反序列化后重新计算
- 没有
- 您可以在我的代码示例中的 lazy val 定义之前添加 @transient,据我所知,它将完全按照您的要求进行操作
代码证明
object LazySerializationTest extends App {
def serialize(obj: Any): Array[Byte] = {
val bytes = new ByteArrayOutputStream()
val out = new ObjectOutputStream(bytes)
out.writeObject(obj)
out.close()
bytes.toByteArray
}
def deSerialise(bytes: Array[Byte]): MyClass = {
new ObjectInputStream(new ByteArrayInputStream(bytes)).
readObject().asInstanceOf[MyClass]
}
def test(obj: MyClass): Unit = {
val bytes = serialize(obj)
val fromBytes = deSerialise(bytes)
println(s"Original cnt = ${obj.x.cnt}")
println(s"De Serialized cnt = ${fromBytes.x.cnt}")
}
object X {
val cnt = new AtomicInteger()
}
class X {
// Not Serializable
val cnt = X.cnt.incrementAndGet
println(s"Create instance of X #$cnt")
}
class MyClass extends Serializable {
lazy val x = new X
}
// Not initialized
val mc1 = new MyClass
test(mc1)
// Force lazy evaluation
val mc2 = new MyClass
mc2.x
test(mc2) // Failed with NotSerializableException
}