Che cosa significa serializzabile?


136

Cosa significa esattamente che una classe si trova Serializablein Java? O in generale, del resto ...


10
@skaffman Ecco cosa dice per la classe Serializable: Serializability of a class is enabled by the class implementing the java.io.Serializable interface. Classes that do not implement this interface will not have any of their state serialized or deserialized. All subtypes of a serializable class are themselves serializable. The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.
Ritwik Bose il

32
Un'ottima spiegazione se sai già cosa significano serializzato e deserializzato. (Non un complimento.) Tali definizioni ti aiutano a capire meglio il problema tecnicamente una volta e solo una volta, hai già qualche conoscenza su di esso.
Xonatron,

Risposte:


132

La serializzazione sta persistendo un oggetto dalla memoria a una sequenza di bit, ad esempio per il salvataggio sul disco. La deserializzazione è l'opposto: leggere i dati dal disco per idratare / creare un oggetto.

Nel contesto della tua domanda, è un'interfaccia che se implementata in una classe, questa classe può automaticamente essere serializzata e deserializzata da diversi serializzatori.


2
Si noti inoltre che anche tutti i campi non contrassegnati in modo esplicito altrimenti verranno serializzati. Ciò significa che è possibile salvare facilmente una struttura dati complessa semplicemente serializzando l'oggetto root.
Thorbjørn Ravn Andersen,

1
Quindi quando parliamo di "Oggetti", intendiamo l'oggetto istanziato da una classe, o semplicemente "Oggetti Software" come assembly, file, ecc.? E se è quest'ultimo, è solo un modo standardizzato di inviare dati tra programmi e ambienti?
Sunburst275,

1
@ Sunburst275 - in questo caso, questa è la rappresentazione in memoria di una classe in memoria - vale a dire un'istanza di una classe (non ha senso parlare della serializzazione degli assiemi, poiché di solito sono su disco come file che possono semplicemente essere spedito così com'è).
Oded,

44

Sebbene la maggior parte degli utenti abbia già dato la risposta, ma vorrei aggiungere un esempio per coloro che ne hanno bisogno per spiegare l'idea:

Supponiamo che tu abbia una persona di classe come la seguente:

public class Person implements java.io.Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public String firstName;
    public String lastName;
    public int age;
    public String address;

    public void play() {
        System.out.println(String.format(
                "If I win, send me the trophy to this address: %s", address));
    }
    @Override
    public String toString() {
        return String.format(".....Person......\nFirst Name = %s\nLast Name = %s", firstName, lastName);
    }
}

e poi crei un oggetto come questo:

Person william = new Person();
        william.firstName = "William";
        william.lastName = "Kinaan";
        william.age = 26;
        william.address = "Lisbon, Portugal";

È possibile serializzare quell'oggetto su molti flussi. Lo farò su due flussi:

Serializzazione allo standard output:

public static void serializeToStandardOutput(Person person)
            throws IOException {
        OutputStream outStream = System.out;
        ObjectOutputStream stdObjectOut = new ObjectOutputStream(outStream);
        stdObjectOut.writeObject(person);
        stdObjectOut.close();
        outStream.close();
    }

Serializzazione in un file:

public static void serializeToFile(Person person) throws IOException {
        OutputStream outStream = new FileOutputStream("person.ser");
        ObjectOutputStream fileObjectOut = new ObjectOutputStream(outStream);
        fileObjectOut.writeObject(person);
        fileObjectOut.close();
        outStream.close();
    }

Poi:

Deserializza dal file:

public static void deserializeFromFile() throws IOException,
            ClassNotFoundException {
        InputStream inStream = new FileInputStream("person.ser");
        ObjectInputStream fileObjectIn = new ObjectInputStream(inStream);
        Person person = (Person) fileObjectIn.readObject();
        System.out.println(person);
        fileObjectIn.close();
        inStream.close();
    }

Grazie. Penso di averlo capito adesso.
Sunburst275,

40

Significa che le istanze della classe possono essere trasformate in un flusso di byte (ad esempio, per essere salvate in un file) e quindi nuovamente convertite in classi. Questa ricarica potrebbe avvenire in una diversa istanza del programma, o anche su una macchina diversa. La serializzazione (in qualsiasi lingua) comporta ogni sorta di problemi, specialmente quando si hanno riferimenti ad altri oggetti all'interno di quello serializzabile.


15

Ecco una spiegazione dettagliata della serializzazione : (il mio blog)

serializzazione:

La serializzazione è il processo di serializzazione dello stato di un oggetto che viene rappresentato e memorizzato sotto forma di una sequenza di byte. Questo può essere memorizzato in un file. Il processo per leggere lo stato dell'oggetto dal file e ripristinarlo si chiama deserializzazione.

Qual è la necessità della serializzazione?

Nell'architettura moderna, è sempre necessario memorizzare lo stato dell'oggetto e quindi recuperarlo. Ad esempio in Hibernate, per memorizzare un oggetto dovremmo rendere la classe serializzabile. Ciò che fa è che una volta salvato lo stato dell'oggetto sotto forma di byte, può essere trasferito su un altro sistema che può quindi leggere dallo stato e recuperare la classe. Lo stato dell'oggetto può provenire da un database o da un jvm diverso o da un componente separato. Con l'aiuto della serializzazione possiamo recuperare lo stato dell'Oggetto.

Esempio di codice e spiegazione:

Per prima cosa diamo un'occhiata alla classe di oggetti:

public class Item implements Serializable{

    /**
    *  This is the Serializable class
    */
    private static final long serialVersionUID = 475918891428093041L;
    private Long itemId;
    private String itemName;
    private transient Double itemCostPrice;
    public Item(Long itemId, String itemName, Double itemCostPrice) {
        super();
        this.itemId = itemId;
        this.itemName = itemName;
        this.itemCostPrice = itemCostPrice;
      }

      public Long getItemId() {
          return itemId;
      }

     @Override
      public String toString() {
          return "Item [itemId=" + itemId + ", itemName=" + itemName + ", itemCostPrice=" + itemCostPrice + "]";
       }


       public void setItemId(Long itemId) {
           this.itemId = itemId;
       }

       public String getItemName() {
           return itemName;
       }
       public void setItemName(String itemName) {
            this.itemName = itemName;
        }

       public Double getItemCostPrice() {
            return itemCostPrice;
        }

        public void setItemCostPrice(Double itemCostPrice) {
             this.itemCostPrice = itemCostPrice;
        }
}

Nel codice sopra si può vedere che la classe Item implementa Serializable .

Questa è l'interfaccia che consente a una classe di essere serializzabile.

Ora possiamo vedere una variabile chiamata serialVersionUID è inizializzata su variabile Long. Questo numero viene calcolato dal compilatore in base allo stato della classe e agli attributi della classe. Questo è il numero che aiuterà jvm a identificare lo stato di un oggetto quando legge lo stato dell'oggetto dal file.

Per questo possiamo dare un'occhiata alla documentazione Oracle ufficiale:

Il runtime di serializzazione associa a ciascuna classe serializzabile un numero di versione, chiamato serialVersionUID, che viene utilizzato durante la deserializzazione per verificare che il mittente e il destinatario di un oggetto serializzato abbiano caricato classi per quell'oggetto compatibili rispetto alla serializzazione. Se il destinatario ha caricato una classe per l'oggetto che ha un serialVersionUID diverso da quello della classe del mittente corrispondente, la deserializzazione si tradurrà in InvalidClassException. Una classe serializzabile può dichiarare esplicitamente la propria serialVersionUID dichiarando esplicitamente un campo denominato "serialVersionUID" che deve essere statico, finale e di tipo lungo: ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; Se una classe serializzabile non dichiara esplicitamente un serialVersionUID, quindi il runtime di serializzazione calcolerà un valore serialVersionUID predefinito per quella classe in base a vari aspetti della classe, come descritto nelle Specifiche di serializzazione degli oggetti Java (TM). Tuttavia, si consiglia vivamente che tutte le classi serializzabili dichiarino esplicitamente i valori serialVersionUID, poiché il calcolo serialVersionUID predefinito è altamente sensibile ai dettagli della classe che possono variare a seconda delle implementazioni del compilatore e può quindi provocare inattese InvalidClassExceptions durante la deserializzazione. Pertanto, per garantire un valore serialVersionUID coerente tra le diverse implementazioni del compilatore java, una classe serializzabile deve dichiarare un valore serialVersionUID esplicito. Si consiglia inoltre vivamente che dichiarazioni esplicite serialVersionUID utilizzino il modificatore privato ove possibile,

Se hai notato che abbiamo usato un'altra parola chiave che è temporanea .

Se un campo non è serializzabile, deve essere contrassegnato come transitorio. Qui abbiamo contrassegnato itemCostPrice come transitorio e non vogliamo che sia scritto in un file

Ora diamo un'occhiata a come scrivere lo stato di un oggetto nel file e quindi leggerlo da lì.

public class SerializationExample {

    public static void main(String[] args){
        serialize();
       deserialize();
    } 

    public static void serialize(){

         Item item = new Item(1L,"Pen", 12.55);
         System.out.println("Before Serialization" + item);

         FileOutputStream fileOut;
         try {
             fileOut = new FileOutputStream("/tmp/item.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut);
             out.writeObject(item);
             out.close();
             fileOut.close();
             System.out.println("Serialized data is saved in /tmp/item.ser");
           } catch (FileNotFoundException e) {

                  e.printStackTrace();
           } catch (IOException e) {

                  e.printStackTrace();
           }
      }

    public static void deserialize(){
        Item item;

        try {
                FileInputStream fileIn = new FileInputStream("/tmp/item.ser");
                ObjectInputStream in = new ObjectInputStream(fileIn);
                item = (Item) in.readObject();
                System.out.println("Serialized data is read from /tmp/item.ser");
                System.out.println("After Deserialization" + item);
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        } catch (IOException e) {
               e.printStackTrace();
        } catch (ClassNotFoundException e) {
               e.printStackTrace();
        }
     }
}

In quanto sopra possiamo vedere un esempio di serializzazione e deserializzazione di un oggetto.

Per questo abbiamo usato due classi. Per serializzare l'oggetto abbiamo usato ObjectOutputStream. Abbiamo usato il metodo writeObject per scrivere l'oggetto nel file.

Per la deserializzazione abbiamo usato ObjectInputStream che legge dall'oggetto dal file. Utilizza readObject per leggere i dati dell'oggetto dal file.

L'output del codice sopra sarebbe simile a:

Before SerializationItem [itemId=1, itemName=Pen, itemCostPrice=12.55]
Serialized data is saved in /tmp/item.ser
After DeserializationItem [itemId=1, itemName=Pen, itemCostPrice=null]

Si noti che itemCostPrice dall'oggetto deserializzato è nullo in quanto non è stato scritto.


2
Grazie per questa spiegazione dettagliata.
Promessa Preston,

Questa è una bella spiegazione! Grazie! Ma a dire il vero, questa voce sembra molto più pulita di quella sul tuo blog. Comunque, questo ha aiutato molto!
Sunburst275,

11

La serializzazione comporta il salvataggio dello stato corrente di un oggetto in un flusso e il ripristino di un oggetto equivalente da quel flusso. Il flusso funziona come contenitore per l'oggetto


1
Questa definizione sembra più precisa. Grazie.
Promessa Preston,

6

Serializable è chiamato come un'interfaccia ma è più simile a un flag al sottosistema Serialization, in fase di esecuzione. Dice che questo oggetto può essere salvato. Verranno salvate tutte le variabili di istanza di Oggetti ad eccezione di nessun oggetto serializzabile e di quelli contrassegnati come volatili.

Immagina che la tua applicazione possa cambiare colore come opzione, senza mantenere quell'impostazione esterna dovrai cambiare il colore ogni volta che la esegui.


5
Non è una "bandiera per il compilatore". È un flag per il sottosistema di serializzazione, in fase di esecuzione.
Marchese di Lorne,

1
@EJP - Grazie, non lo sapevo
AphexMunky il

Con rispetto, perché scriverlo quando non sai che è vero? Hai anche lasciato fuori 'transitorio'. Nel complesso una risposta scadente, scusa.
Marchese di Lorne,

19
Se non lo avessi scritto, non sarei stato corretto e starei peggio. Anche tutte le altre risposte sono state interrotte. Non hai nemmeno scritto una risposta, stai solo trollando altre persone.
AphexMunky

4

La serializzazione è una tecnica per archiviare o scrivere oggetti e dati in file. Usando ObjectOutputStreame FileOutputStreamclassi. Queste classi hanno i loro metodi specifici per mantenere gli oggetti. piacewriteObject();

per una chiara esplosione con figure. Per maggiori informazioni vedere qui


2

Presentare da un'altra prospettiva. La serializzazione è un tipo di interfaccia chiamata "interfaccia marker". Un'interfaccia marker è un'interfaccia che non contiene dichiarazioni di metodi, ma designa semplicemente (o "segna") una classe che implementa l'interfaccia come avente alcune proprietà. Se capisci il polimorfismo, questo avrà molto senso. Nel caso dell'interfaccia dell'indicatore Serializable, il metodo ObjectOutputStream.write (Object) fallirà se il suo argomento non implementa l'interfaccia. Questo è un potenziale errore in Java, potrebbe essere stato ObjectOutputStream.write (Serializable)

Altamente raccomandato: leggere l'articolo 37 da Java efficace di Joshua Bloch per saperne di più.


2

Serializzazione: scrittura dello stato dell'oggetto su file / rete o ovunque. (Significa il modulo supportato da oggetto Java in File modulo supportato o modulo supportato in rete)

Deserializzazione: lettura dello stato dell'oggetto da file / rete o ovunque. (Modulo medio di file / rete supportato in modulo supportato oggetto Java)


1

Solo per aggiungere alle altre risposte e per quanto riguarda la generalità. La serializzazione è talvolta nota come archiviazione, ad esempio in Objective-C.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.