2016-03-09 8 views
6

Se serializzare un oggetto Class (per esempio, HashMap.class), e quindi deserializzare in un altro esempio di JVM, si scopre che la classe deserializzato è identico a quello attualmente caricato:In che modo Java può deserializzare oggetti Class conservando la propria identità sugli oggetti Class attualmente caricati?

import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.util.HashMap; 

final class DeserializationTest { 

    static String path = "/home/suseika/test.ser"; 
    static Class<HashMap> cls = HashMap.class; 

    public static void main(String[] args) throws Exception { 
     if (args[0].equals("serialize")) { 
      serialize(); 
     } else if (args[0].equals("deserialize")) { 
      final Object deserialized = deserialize(); 

      // The important line, prints "true" 
      System.out.println(deserialized == cls); 
     } 
    } 

    static Object deserialize() throws Exception { 
     ObjectInputStream in = new ObjectInputStream(new FileInputStream(path)); 
     return in.readObject(); 
    } 

    static void serialize() throws Exception { 
     FileOutputStream fileOut = new FileOutputStream(path); 
     ObjectOutputStream out = new ObjectOutputStream(fileOut); 
     out.writeObject(cls); 
     out.close(); 
     fileOut.close(); 
    } 
} 

Come è Java in grado di deserializzare gli oggetti in questo caso in modo che l'identità sia preservata? Class non sembra implementare writeObject()/readObject()/readResolve().

Questo comportamento può essere interrotto con il caricamento di una particolare classe/utilizzando un particolare programma di caricamento classi/utilizzando una particolare configurazione JVM/facendo qualcosa durante la serializzazione? Esistono casi in cui lo Class caricato non corrisponde a quello deserializzato? In altre parole, posso fare affidamento su questo comportamento nella mia applicazione per serializzare e deserializzare gli oggetti Class?

+3

IMHO: un oggetto di classe deserializzato dovrebbe essere indistinguibile di un oggetto di classe "standard" dello stesso tipo. Vedi https://docs.oracle.com/javase/7/docs/api/serialized-form.html#java.lang.Class – Xvolks

risposta

2

In che modo Java è in grado di deserializzare gli oggetti in questo caso in modo da preservare l'identità?

Questo perché le istanze di classe sono memorizzate nella cache dal classloader.

Does Java guarantee that Object.getClass() == Object.getClass()?

Può questo comportamento essere rotto con il caricamento di una particolare classe/utilizzando un particolare programma di caricamento classe/utilizzando un particolare configurazione JVM/fare qualcosa durante la serializzazione?

Per le istanze serializzati di classi dai pacchetti non iniziano java.* questo può essere rotto utilizzando diversi classloader in ObjectInputStream (un esempio here).

Per le classi in java.* come il vostro caso (java.lang.Class), solo la classe bootstrap loader li può caricare, e dato che la definizione di classe è unica per classe loader (garantita dalla JVM spec)

In altre parole, posso contare su questo comportamento nella mia applicazione per serializzare e deserializzare oggetti di classe

+0

Sicuramente 'Class'es vengono memorizzati nella cache dal classloader, ciò che mi sorprende è il fatto che la deserializzazione di una' Class' creata in _another_istanza JVM conserva l'identità con istanze di 'Class' nell'istanza JVM corrente. Quindi, se utilizzo la logica di deserializzazione standard di 'ObjectInputStream', utilizzo solo un singolo classloader e non ho definizioni diverse per le classi con gli stessi nomi canonici, quindi posso essere sicuro che l'identità degli oggetti' Class' sarà preservata dopo la deserializzazione? – gvlasov

+0

Si noti che ciò a cui si fa riferimento come "Classe" è in realtà un'istanza di classe 'Class' (scusa per lo scioglilingua). Pertanto non è possibile avere più istanze per ogni programma di caricamento classi che rappresenta lo stesso FQN di classe. Quindi la risposta è sì, puoi star sicuro – idelvall

+0

Notare anche che deserializzare un oggetto serializzato (da qualsiasi classe che include 'Class') può portare ad errori se le versioni differiscono ... – idelvall

0

In che modo Java è in grado di deserializzare gli oggetti in questo caso in modo che l'identità venga preservata? Class non sembra implementare writeObject()/readObject()/readResolve().

Non ha bisogno di attuare readObject() o writeObject() Per realizzare ciò, ma potrebbe farlo attuando readResolve(), o dalla logica speciale in ObjectInputStream.

+0

Grazie, ma questo dovrebbe essere un commento, non una risposta. Ho modificato il mio post menzionando che 'Class' non ha' readResolve() 'neanche. – gvlasov

+0

Non è un commento. Ho ora citato la domanda a cui risponde questa risposta.Poiché sembra che sia stata una risposta errata, l'ho modificata. – EJP