Как работает сериализация ленивых полей?

Я знаю преимущества ленивых полей, когда по некоторым причинам требуется отсроченная оценка ценностей. Мне было интересно, что такое поведение ленивых полей с точки зрения сериализации.

Рассмотрим следующий класс.

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

Вопросов:

  • Если экземпляр экземпляра MyClass сериализуется, делает ли ленное поле также сериализованным?
  • Изменяется ли поведение сериализации при доступе к полю или нет до сериализации? Я имею в виду, если я не вызываю оценку поля, считается ли он нулевым?
  • Является ли механизм сериализации причиной неявной оценки ленивого поля?
  • Есть ли простой способ избежать сериализации переменной и получения значения, повторно рассчитанного еще раз лениво после десериализации? Это должно происходить независимо от оценки поля.

Ответ 1

ответы

  1. Да, если поле уже было инициализировано, если вы не можете направить его как метод. Значение не вычисляется → не сериализовано, но доступно после сериализации.
  2. Если вы не касались поля, он сериализован почти так же, как и простой метод "def", вам не нужно, чтобы он был сериализуемым, он будет пересчитан после де-сериализации
  3. нет
  4. Вы можете добавить @transient до определения ленивого val в моем примере кода, так как я понимаю, что он будет делать именно то, что вы хотите

Код для доказательства

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

}