【问题标题】:How does serialization of lazy fields work?惰性字段的序列化如何工作?
【发布时间】:2015-03-09 01:22:54
【问题描述】:

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

考虑以下类。

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

问题:

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

【问题讨论】:

  • “序列化”是什么意思?我希望你没有在 scala 中使用标准的 java 序列化。您使用的是哪个序列化库?

标签: scala serialization


【解决方案1】:

答案

  1. 是的,如果字段已经初始化,如果没有,你可以把它当作一个方法。值未计算 -> 未序列化,但在反序列化后可用。
  2. 如果你没有触摸字段,它几乎是序列化的,因为它是一个简单的'def'方法,你不需要它的类型本身是可序列化的,它会在反序列化后重新计算
  3. 没有
  4. 在我的代码示例中,您可以在惰性 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

}

【讨论】:

  • 注意:将惰性字段标记为 @transient 将(可能)不会将惰性 val 在内部使用的位掩码标记为 @transient。因此,它们将被序列化。反序列化时,您最终会得到一个初始化/未初始化的惰性值。
  • 我尝试在上面的代码中添加瞬态,看起来完全没问题。我会说如果掩码没有被标记为瞬态它是 scalac 错误
  • 好吧,无论哪种情况,它都是一个错误。掩码可以在多个惰性值之间共享。如果其中一个是@transient 而另一个不是,你会怎么做? (是的,正确的行为是不分享它们。不幸的是,我对此表示怀疑)。
  • Tx EugeneZhulenev 和 gzm0,信息量很大。顺便说一句,我怎么知道这个提交包含在哪个版本的 scala 中?
  • 我想我找到了,在提交信息之后我可以点击获取发布标签列表。
猜你喜欢
  • 2011-06-13
  • 1970-01-01
  • 1970-01-01
  • 2015-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-24
相关资源
最近更新 更多