惰性字段的序列化如何工作?

Nic*_*aro 14 serialization scala

当出于某些原因需要推迟评估值时,我知道惰性字段的好处.我想知道在序列化方面懒惰字段的行为是什么.

考虑以下课程.

class MyClass {
  lazy val myLazyVal = {...}
  ...
}
Run Code Online (Sandbox Code Playgroud)

问题:

  • 如果MyClass的一个实例被序列化,那么惰性字段是否也被序列化了?
  • 如果在序列化之前访问了字段,序列化的行为是否会发生变化?我的意思是,如果我不对该字段进行评估,它是否被认为是空的
  • 序列化机制是否会引发对惰性字段的隐式评估?
  • 是否有一种简单的方法可以避免变量的序列化并在反序列化后懒惰再次重新计算值?这应该独立于该领域的评估.

Eug*_*nev 9

答案

  1. 是,如果字段已经初始化,如果不是,您可以将其作为一种方法.值不计算 - >未序列化,但在序列化后可用.
  2. 如果你没有触及字段,它的序列化几乎就像它是一个简单的'def'方法,你不需要它的类型可以自行序列化,它将在反序列化后重新计算
  3. 没有
  4. 您可以在我的代码示例中在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

}
Run Code Online (Sandbox Code Playgroud)

  • 看起来已经修好了https://github.com/scala/scala/commit/bcfe76ee68 (2认同)