JavaRush /Java Blog /Random-IT /Come funziona la serializzazione in Java
ramhead
Livello 13

Come funziona la serializzazione in Java

Pubblicato nel gruppo Random-IT
In questo articolo spiegheremo cos'è la serializzazione e come funziona in Java. Come funziona la serializzazione in Java - 1

introduzione

La serializzazione degli oggetti è la capacità di un oggetto di archiviare una copia completa di se stesso e di qualsiasi altro oggetto a cui fa riferimento utilizzando un flusso di output (ad esempio, in un file esterno). In questo modo, l'oggetto può essere ricreato dalla copia serializzata (salvata) un po' più tardi, quando necessario. La serializzazione degli oggetti, una nuova funzionalità introdotta in JDK 1.1, fornisce una funzione per convertire gruppi o singoli oggetti, in un flusso di bit o un array di byte, per l'archiviazione o la trasmissione su una rete. E come affermato, un dato flusso di bit o un array di byte può essere riconvertito in oggetti Java. Ciò avviene principalmente in modo automatico grazie alle classi ObjectInputStreame ObjectOutputStream. Il programmatore può decidere di implementare questa funzionalità implementando l'interfaccia Serializabledurante la creazione della classe. Il processo di serializzazione è noto anche come marshalling degli oggetti , mentre la deserializzazione è nota come unmarshaling . La serializzazione è un meccanismo che consente a un oggetto di salvare una copia di se stesso e di tutti gli altri oggetti a cui fa riferimento in un file esterno utilizzando l'estensione ObjectOutputStream. Gli oggetti salvati possono essere strutture dati, diagrammi, oggetti di classe JFrameo qualsiasi altro oggetto, indipendentemente dal loro tipo. Allo stesso tempo, la serializzazione memorizza informazioni sul tipo di oggetto in modo che successivamente, una volta deserializzate, tali informazioni vengano utilizzate per ricreare l'esatto tipo di oggetto che era. Pertanto, la serializzazione fornisce le seguenti funzionalità:
  • Un sistema per archiviare oggetti, ovvero: salvare le loro proprietà su un file esterno, su disco o su un database.
  • Sistema di chiamata di procedura remota.
  • Un sistema di distribuzione di oggetti, ad esempio, in componenti software come COM, COBRA.
  • Sistema per identificare le variazioni dei dati variabili nel tempo.
Per comprendere appieno il concetto di serializzazione, è necessario avere una chiara comprensione degli altri due concetti: persistenza dell'oggetto e persistenza del thread. Qui parleremo un po 'di ciascuno di essi per ricordarlo. Una loro spiegazione completa richiederebbe un capitolo separato per ciascuno di questi concetti.

Flussi:

Ogni programma deve scrivere i propri dati in una posizione di archiviazione o in una pipe e ogni programma deve leggere i dati da una pipe o in una posizione di archiviazione. In Java, questi canali in cui i programmi scrivono e da cui i programmi leggono i dati sono chiamati Streams ( Stream) . Come funziona la serializzazione in Java - 2
Figura 1. Rappresentazione grafica dei thread
I flussi si dividono principalmente in due tipologie:
  • Classi di flusso di byte chiamate *Streams
  • Classi di flussi di caratteri denominate *Reader e *Writer
Ogni flusso di scrittura dati contiene una serie di metodi di scrittura. E ogni thread di lettura dei dati, di conseguenza, ha un insieme simile di metodi di lettura. Una volta creato il thread, è necessario chiamare tutti questi metodi.

Persistenza

La persistenza di un oggetto è la capacità di un oggetto di vivere o, in altre parole, di “sopravvivere” all'esecuzione di un programma. Ciò significa che qualsiasi oggetto creato in fase di esecuzione viene distrutto dallo scavenger JVM ogni volta che l'oggetto non viene più utilizzato. Ma se viene implementata l'API di persistenza, questi oggetti non verranno distrutti dallo scavenger JVM, ma potranno “vivere”, il che rende possibile accedervi anche al successivo avvio dell'applicazione. In altre parole, persistenza significa che esiste una durata di vita per un oggetto, indipendente dalla durata dell'applicazione in esecuzione. Un modo per implementare la persistenza è archiviare gli oggetti da qualche parte in un file o database esterno e quindi ripristinarli in un secondo momento utilizzando tali file o il database come origini. È qui che entra in gioco la serializzazione. Qualsiasi oggetto non persistente esiste finché la JVM è in esecuzione. Gli oggetti serializzati sono semplicemente oggetti convertiti in flussi, che vengono poi salvati in un file esterno o trasferiti in rete per l'archiviazione e il ripristino.

Implementazione dell'interfaccia Serializable

Qualsiasi classe deve implementare un'interfaccia java.io.Serializableper serializzare gli oggetti di quella classe. L'interfaccia Serializablenon ha metodi e contrassegna solo la classe in modo che possa essere identificata come serializzabile. È possibile salvare solo i campi di un oggetto classe serializzato. I metodi o i costruttori non vengono archiviati come parte del flusso serializzato. Se un oggetto funge da riferimento a un altro oggetto, anche i campi di quell'oggetto vengono serializzati se la classe di quell'oggetto implementa l'interfaccia Serializable. In altre parole, il grafico di questo oggetto così ottenuto è completamente serializzabile. Un oggetto grafico include un albero o una struttura di campi di un oggetto e dei suoi sottooggetti. Due classi principali che aiutano a implementare l'interfaccia Seriliazable:
  • ObjectInputStream
  • ObjectOutputStream
Listato 1. Esempio di una classe semplice per mostrare la serializzazione
import java.io.*;
public class RandomClass implements Serializable {
 // Генерация рандомного значения
 private static int r() {
        return (int)(Math.random() * 10);
 }
    private int data[];
    // Конструктор
public RandomClass() {
        datafile = new int[r()];
        for (int i=0; i<datafile.length; i++)
        datafile[i]=r();
 }
    public void printout() {
 System.out.println("This RandomClass has "+datafile.length+" random integers");
 for (int i=0; i<datafile.length; i++) {
        System.out.print(datafile[i]+":");
        System.out.println();
    }
}
Nel codice precedente viene creata una classe serializzabile perché "contrassegnato" dall'interfaccia di serializzazione. La classe crea un array di numeri interi casuali quando ne viene creata un'istanza. Il codice seguente mostra la possibilità di scrivere oggetti in un flusso utilizzando ObjectOutputStream. Il programma ha un array di numeri interi, ma per la serializzazione non dobbiamo iterare sui suoi oggetti interni. L'interfaccia Seriliazablese ne occupa automaticamente. Listato 2. Un semplice esempio di serializzazione di oggetti per l'output in un file
import java.io.*;
import java.util.*;
public class OutSerialize {
    public static void main (String args[]) throws IOException {
        RandomClass rc1 = new RandomClass();
        RandomClass rc2 = new RandomClass();
//создание цепи потоков с потоком вывода an object в конце
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("objects.dat"));
        Date now = new Date(System.currentTimeMillis());
//java.util.* был импортирован для использования класса Date
        out.writeObject(now);
        out.writeObject(rc1);
        out.writeObject(rc2);
out.close();
        System.out.println("I have written:");
System.out.println("A Date object: "+now);
        System.out.println("Two Group of randoms");
rc1.printout();
rc2.printout();
 }
}
Il codice seguente dimostra le capacità della classe ObjectInputStream, che legge i dati serializzati da un file esterno in un programma. Si noti che gli oggetti vengono letti nello stesso ordine in cui sono stati scritti nel file. Listato 3. Lettura di oggetti serializzati o Deserializzazione
import java.io.*;
import java.util.*;
public class InSerialize {
 public static void main (String args[]) throws  IOException, ClassNotFoundException {
    ObjectInputStream in =  new ObjectInputStream (new FileInputStream("objects.dat"));
 Date d1 = (Date)in.readObject();
 RandomClass rc1 = (RandomClass)in.readObject();
    RandomClass rc2 = (RandomClass)in.readObject();
    System.out.println("I have read:");
    System.out.println("A Date object: "+d1);
    System.out.println("Two Group of randoms");
    rc1.printout();
rc2.printout();
 }
}
Quasi tutte le classi Java possono essere serializzate, comprese le classi AWT. Un frame, che è una finestra, contiene un insieme di componenti grafici. Se il frame è serializzato, il motore di serializzazione se ne occupa e serializza tutti i suoi componenti e dati (posizione, contenuto, ecc.). Alcuni oggetti di classe Java non possono essere serializzati perché contengono dati che fanno riferimento a risorse temporanee del sistema operativo. Ad esempio classi java.io.FileInputStreame java.lang.Thread. Se un oggetto contiene riferimenti a elementi non serializzabili, l'intera operazione di serializzazione fallirà e verrà generata un'eccezione NotSerializableException. Se un oggetto fa riferimento a un riferimento di un oggetto non serializzato, può essere serializzato utilizzando la parola chiave transitoria . Listato 4. Creazione di oggetti serializzabili utilizzando la parola chiave transient
public class Sclass implements Serializable{
public transient Thread newThread;
//помните, что поток(поток параллельного исполнения) по умолчанию не сериализуемый класс
    private String studentID;
    private int sum;
}

Sicurezza nella serializzazione

La serializzazione di una classe in Java implica il passaggio di tutti i suoi dati a un file o database esterno tramite un flusso. Possiamo limitare i dati che verranno serializzati ogni volta che lo desideriamo. Ci sono due modi per farlo:
  • Ogni parametro di classe dichiarato come transitorio non è serializzato (per impostazione predefinita, tutti i parametri di classe sono serializzati)
  • Oppure, ogni parametro della classe che vogliamo serializzare è contrassegnato da un tag Externalizable(per impostazione predefinita, nessun parametro viene serializzato).
Un campo dati non verrà serializzato con ObjectOutputStream, quando richiamato su un oggetto, se il campo dati di quell'oggetto è contrassegnato come transitorio . Per esempio: private transient String password. D'altra parte, per dichiarare esplicitamente i dati di un oggetto come serializzabili, dobbiamo contrassegnare la classe come ExternalizablewriteExternalin grado readExteranldi scrivere e leggere esplicitamente i dati di quell'oggetto.

Conclusione

La funzionalità della serializzazione degli oggetti viene utilizzata in molti sistemi distribuiti come metodo per trasferire dati. Ma la serializzazione rivela dettagli nascosti, distruggendo così l’autenticità dei tipi di dati astratti, che a sua volta distrugge l’incapsulamento. Allo stesso tempo, è bello sapere che i dati dell'oggetto serializzato sono gli stessi dati presenti nell'oggetto originale. Questa è anche una grande opportunità per implementare un'interfaccia ObjectInputValidatione sovrascrivere un metodo validateObject(), anche se vengono utilizzate più righe di codice. Se l'oggetto non viene trovato, allora possiamo lanciare un'eccezione in modo appropriato InvalidObjectException. Articolo originale: Come funziona la serializzazione in Java
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION