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

标签 scala serialization

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

考虑下面的类。

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

问题:

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

最佳答案

答案

  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

}

关于scala - 惰性字段的序列化如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27882307/

相关文章:

Scala:返回 bool 值的模式匹配的缩写形式

hibernate 尝试序列化标记为@Transient 的字段

scala - 如何在Scalatra中定义子资源路由

scala - 如何计算数据框中每一列每个不同值的出现?

android - DexOpt : illegal method access with Gson TypeToken

java - spring api - jackson 将一个对象序列化为一个数组

c# - AppFabric 缓存 - 它对对象的序列化和反序列化要求是什么?

java - 我需要同步 writeObject() 吗?

scala - 对象 SparkSession 不是包 org.apache.spark.sql 的成员

scala - 使用后台进程退出 repl 控制台