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

时间:2015-01-10 23:33:09

标签: scala serialization

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

考虑以下课程。

class MyClass {
  lazy val myLazyVal = {...}
  ...
}

问题:

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

1 个答案:

答案 0 :(得分:9)

<强>答案

  1. 如果字段已经初始化,则为是,如果不是,您可以将其作为一种方法。不计算值 - &gt;未序列化,但在序列化后可用。
  2. 如果你没有触及字段,它的序列化几乎就像它是一个简单的'def'方法,你不需要它的类型可以自行序列化,它将在反序列化后重新计算
  3. 没有
  4. 你可以在我的代码示例中在lazy val定义之前添加@transient,因为我知道它会完全符合你的需要
  5. 要验证的代码

    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
    
    }