2015-01-10 16 views
11

Conosco i vantaggi dei campi pigri quando per alcuni motivi è necessaria una valutazione dei valori posticipata. Mi chiedevo quale fosse il comportamento dei campi pigri in termini di serializzazione.Come funziona la serializzazione dei campi pigri?

Considerare la seguente classe.

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

Domande:

  • Se un'istanza di MyClass è serializzato, fa il campo pigro ottenere serializzato troppo?
  • Il comportamento della serializzazione cambia se al campo è stato effettuato l'accesso o meno prima della serializzazione? Voglio dire, se non causo la valutazione del campo, è considerato come nullo?
  • Il meccanismo di serializzazione provoca una valutazione implicita del campo pigro?
  • C'è un modo semplice per evitare la serializzazione della variabile e ottenere il valore ricalcolato ancora una volta pigramente dopo la deserializzazione? Questo dovrebbe accadere indipendentemente dalla valutazione del campo.
+0

quello che fare mea n per "serializzazione"? Spero tu non stia usando la serializzazione java standard in scala. Quale libreria di serializzazione stai usando? –

risposta

7

Risposte

  1. Sì se campo è stato già inizializzato, se non si può calpestare come un metodo. Il valore non è calcolato -> non serializzato, ma disponibile dopo la serializzazione.
  2. Se non è stato toccato campo E 'serializzato quasi come si tratta di un metodo semplice 'def', non è necessario il suo tipo ad essere serializzabile se stessa, sarà ricalcolata dopo de-serializzazione
  3. No
  4. È può aggiungere @transient prima della definizione val pigro nel mio esempio di codice, se ho capito bene farà esattamente quello che vuoi

codice per dimostrare

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 

} 
+1

Attenzione: Marcare il campo lazy come '@ transient' (probabilmente) non segnerà le maschere di bit che il val lazy usa internamente come' @ transient'. Pertanto, saranno serializzati. Finirai con un val pigro male inizializzato/unitializzato quando deserializzi. – gzm0

+0

Ho provato ad aggiungere transient al codice sopra e sembra che sia completamente ok. Direi che se la maschera non è marcata come transitoria è il bug scalac –

+0

Beh, è ​​un bug in entrambi i casi quindi. La maschera può essere condivisa tra più lazy vals. Se uno di questi è '@ transient 'e l'altro no, cosa fai? (Sì, il comportamento corretto sarebbe quello di non condividerli allora. Purtroppo ho i miei dubbi a riguardo). – gzm0

Problemi correlati