Una delle principali novitàdel JDK1.1 è sicuramente rappresentata dalla serializzazione.
Inquesto articolo vedremo brevemente in cosa consiste e quali sono i vantaggiche abbiamo utilizzando questa tecnica molto semplice.
Che cosa é la serializzazione
Lutilizzo di questa tecnica permette di ovviare ad un inconveniente molto frequente nella programmazione di applicazioniche permettano la creazione e la editazione di una qualche struttura dati. Supponiamo di avere una applicazione che permette di creare ed editare una lista di oggetti. Una volta che questa struttura dati è stata creata vi è il problema di salvarne il contenuto per eventualmente,ripristinarlo in un secondo tempo.
Prima del JDK1.1 come si doveva fare? Bisognava decidere un certo protocollo di memorizzazione su un file. Sedovevamo salvare dei record di dati di struttura simile avevamo dei vantaggiin quanto scrivevamo sullo stream una struttura fissa in modo testo o altro. Ma le cose divenivano sempre più complicate se la struttura datiera un po più complessa. Se la struttura consisteva in un albero,oggetti legati tra loro da una relazione padre figlio, o liste bilatereo altro, il problema assumeva una certa dimensione. Bisognava implementare due enormi metodi di conversione della struttura in un qualcosa di sequenziale,salvarlo e poi ripristinarlo e ricostruire la struttura originaria. Con la serializzazione questo problema diventa una banalità.
Come si indica che un oggetto è serializzabile
In Java non è cosa rara incontrare delle interfacce che non presentano la dichiarazione di metodi. Esse servono semplicemente a segnare o firmare una determinata classe. Nel nostro caso la interfaccia che permette di stabilire che una classe è serializzabileè la java.io.Serializable. Se un oggetto implementalinterfaccia Serializable, esso è serializzabile cioè può essere salvato, o meglio reso persistente, e poi ripristinato. La cosa importante è che loggetto ripristinato abbia le stesse proprietà delloggetto salvato. Questo non è completamentevero in quanto vi è la possibilità di definire alcune proprietà come transient per cui ne viene salvata listanza ma in fase di ripristino i suoi campi assumono i loro valori di default.
Supponiamo di avere una classe di nome Struttura. Per renderla serializzabile basterà scrivere
publicclass Struttura extends Parent implements java.io.Serializable {
....................
...................
}
Parent è una ipotetica classe di cui Struttura è estensione (ovviamente può anche non esserci, è solo un esempio). Una cosa da dire assolutamente è che, per essere serializzabile, una classe deve utilizzare alsuo interno classi serializzabili. Se una variabile pubblica di Struttura non fosse serializzabile, essa non sarebbe effettivamente serializzabile. Il processo di serializzazione, infatti, è ricorsivo.
Con il JDK1.1esiste uno strumento che permette di verificare se un a classe è, oppure no, serializzabile. Questo si chiama serialver.
Chiamando questo programma con lopzione -show apparirà una finestra nella quale metterete il nome completo della classe che volete esaminare. Se la classe è serializzabile apparirà un valore identificativo della classe stessa, altrimenti non apparirà nulla.
In questo modo potrete verificare le vostre classi. La cosa, a dire ilvero non funziona molto bene in quanto se provate a verificare se la classe java.awt.Image è serializzabile avete risposta positivamentre se poi provate a serializzarla avete un errore. Questo èun bug conosciuto della JDK1.1 che si estende, oltre che alla classe Image, anche ai TextComponent nella beta3. Mah! Evidentemente il serialver verifica se la classe implementa Serializable insieme a tuttele classi utilizzate e niente altro, senza verificarne il funzionamento.
Il numero che appare nel serialver non è altro che un identificativo della classe e della sua versione. Infatti,quando una struttura viene serializzata, può capitare che diverseistanze di una stessa siano scritte sullo stream. Nel caso in cui questoavvenga, la prima volta si scriverà la classe con tutte le sue informazionie successivamente si scriverà solamente lidentificativo della classecon i valori caratteristici dellistanza. In questo modo si ottiene anche una buona compressione dei dati scritti.
Unaltra cosa da sottolineare è la gestione delle versioni diverse della stessa classe. Se si rende persistente una classe e la si ripristina bisognerà fare in modo che il fileclass della classe di cui si dispone in fase di ripristino non siaconsiderevolmente differente da quella a disposizione in fase di creazione. Per considerevolmente differente intendiamo che la interfaccia che mettea disposizione non sia diversa. In questo caso si avrebbe quella che èla eccezione della serializzazione cioè java.io.ObjectStreamException.
Come si rende un oggetto persistente
Ora che abbiamo brevemente descritto che cosaè la persistenza, vediamo come si può serializzare una classe.La cosa è molto semplice in quanto il JDK mette a disposizione quelliche sono gli strumenti essenziali alla serializzazione. Questi sono linterfacciajava.io.Serializable e le due nuove classi java.io.ObjectInputStreamed java.io.ObjectOutputStream. Queste classi implementanole interfaccia java.io.ObjectInput ed java.io.ObjectOutputrispettivamente. Queste, a loro volta estendono le interfacce java.io.DataInpute java.io.DataOutput introducendo i metodi readObjecte writeObject. Attraverso questi due metodi è possibile primascrivere e poi rileggere e ricostruire un qualunque oggetto serializzabile.
Supponiamo di voler salvare su un file dinome restore.ser un oggetto che abbiamo creato in una qualche altraparte di una applicazione. Chiamiamo questo oggetto salvato. Scriviamo,allora, il metodo scrivi che permette il salvataggio delloggettoindicato sul file.
Public
void scrivi () {
try{
fos = new FileOutputStream ("restore.ser");
oos = new ObjectOutputStream(fos);
oos.writeObject(salvato);
oos.close();
}
catch
(Ioexception ioe){
System.out.println("Errore:"+ioe.toString());
}//
fine catch
}// fine
metodo scrivi
Il metodo non fa altro che legare un ObjectOutputStreamad un FileOuputStream per poter scrivere sul file loggettoattraverso il metodo writeObject.
Nel caso di ripristino basterà scrivere il seguente metodo leggi.
Public
void leggi () {
try{
fis = new FileInputStream ("restore.ser");
ois = new ObjectInputStream(fis);
salvato = (TipoSalvato)(ois.readObject());
ois.close();
}
catch (Ioexception ioe){
System.out.println("Errore:"+ioe.toString());
}// fine catch
}// fine
metodo leggi
Il metodo di lettura è molto semplice. Lunica cosa da considerare con attenzione riguarda loperazione di cast da fare allatto del readObject. Infatti essa ritorna un Objectper cui tale operazione si rende necessaria. Nel nostro caso abbiamo eseguitouna operazione di cast relativamente al tipo TipoSalvato,tipo realtivo alloggetto salvato.
Conclusioni
In questo breve articolo abbiamo visto checosa è la serializzazione e come si rende persistente un oggetto. Questa tecnica è molto utile e permette di risolvere, in poche righedi codice, problemi che in precedenza portavano via molto tempo, relativamentealla memorizzazione e ricostruzione di strutture dati complesse. Ovviamente la serializzazione non solo quello descritto qui ma offre tecniche piùsofisticate per la gestione delle versioni relativamente alle conversionidi tipo tra versioni diverse di stesse classi. Magari approfondiremo questiargomenti in un successivo articolo.
