Scarica Serializzazione e Deserializzazione di Oggetti in Java: Guida Dettagliata - Prof. Coen Por e più Appunti in PDF di Elementi di Informatica solo su Docsity!
Programmazione concorrente e distribuita
La serializzazione
La serializzazione è un operazione mediante la quale è possibile scrivere su uno stream i valori
contenuti all'interno di un oggetto.
L'operazione inversa è detta de-serializzazione.
La serializzazione consente di:
- Trasferire le informazioni di un oggeto, se lo stream è associato a unc anale di
comunicazione;
- Salvare permanentemente le informazioni di un oggetto, se lo stream è associato ad un
file;
Oggetto identifici Oggetto
Serializzazione Byte Stream Deserializzazione
Le operazioni di scrittura e lettura che avvengono mediante degli stream di oggeti sono definite
tramite le interfacce:
- ObjectOutput , per la scrittura;
- ObjectInput , per la lettura; ObjectOutput
- void close (): Chiude lo stream;
- void flush (): Flush dello stream;
- void writeObject (Object obj): Scrive un oggetto sullo stream sottostante; ObjectInput
- int available (): Ritorna il numero di byte che vengono letti;
- void close (): Chiude l'input stream;
- Object readObject (): Legge un oggetto dallo stream sottostante e lo restituisce (restituisce
un generico oggetto starà al programmatore capire di che tipo sarà);
La serializzazione
Le interfacce sono implementate dalle classi:
- ObjectoutputStream , per la scrittura;
- ObjectInputStream , per la lettura ObjectoutputStream
Implementa i metodi dell'interfaccia ObjectStream:
void writeObject(object obj) throw IOException
La serializzazione dei tipi base di java avviene facendo uso dei metodi messi a disposizione del
linguaggio:
public class Esempio { public static void main(String[] args) throws IOException { String fileName = "tmp.bin"; ObjectOutputStream os = new ObjectOutputStream( new FileOutputStream(fileName)); int i=11; os.writeInt(i); os.flush(); os.close(); } } La deserializzazione
La deserializzazione dei tipi base di java avviene facendo in modo altrettando semplice:
public class Esempio { public static void main(String[] args) throws IOException { String fileName = "tmp.bin"; ObjectInputStream is = new ObjectInputStream( new FileInputStream(fileName)); int letto = newis.readInt(); System.out.println("Letto: " + letto); is.close(); } } La serializzazione
Un oggetto per essere serializzato deve essere istanza di una classe che:
- Implementa l'interfaccia Serializable definita nel package java.io;
- Possiede l'attributo statico:
private static final long serialVersionUID =...
◦ Usato per verificare che le classi usare per serializzare e deserializzare siano compatibili;
◦ Se non definito vien calcolato in modo utonomo da JVM;
Durante la serializzazine vengono scritti i valori di tutti gli attributi, più le altre informazioni che
servono per ricostruire gli oggett al momento della deserializzazione.
Nota bene
Se gli attributi sono dei riferimenti ad altri oggetti, la serializzazione procede in maniera
ricorsiva.
- Tutti gli oggetti che si incontrano devono essere oggetti serializzati.
Tutti i tipi base sono per definizione serializabili. Un oggetto è detto serializabile se la sua classe
o la sua superclassse implementano l'interfaccia Serializable.
Nota bene
- Gli attributi stati non vengono serializzati.
- Gli attributi con modificatore transient non vengono serializzati
Se un oggetto serializzabile ha un riferimento a un oggetto non serializzabile, il codice verrà
- Un'istanza di A
- Un'istanza di B;
Effettua la serializzazione in un file passato come parametro
class creaSerializza { public static void main(String[] args) throws IOException { A a1 = new A(1, "prova"); B b1 = new B(200,a1); if (args.length != 1 ) { System.err.println("Uso: creaSerializza "); System.exit(-1); } File f = new File(args[0]); if (f.exists()) f.delete(); f.createNewFile(); ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream(f)); out.writeObject(b1); out.close(); } }
programma che ricorstruisce la struttura, serializzata in precedenza, da un file passato come
parametro, e stampa il valoer degli attributi
class deserializza { public static void main(String[] args) throws IOException { if (args.length != 1 ) { System.err.println("Uso: deserializza "); System.exit(-1); } File f = new File(args[0]);
if (!f.exists()) { System.err.println("File " + args[0] + " inesistente"); System.exit(-1); } ObjectInputStream in = new ObjectInputStream( new FileInputStream(f)); try { B ref = (B) in.readObject(); System.out.println("A.val = " + ref.getA().getVal()); System.out.println("A.txt = " + ref.getA().getTxt()); System.out.println("B.val = " + ref.getVal()); in.close(); } catch (ClassNotFoundException e) { System.err.println("Errore di deserializzazione"); e.printStackTrace(); I in.close(); System.exit(-1); } } } Stream di oggetti e Socket
Il passaggio di dati attraverso un socket può avvenire utilizzando degli stream di oggetti
costruiti sui ByteStream assocaiti al socket.
- Gli oggetti devono essere istanza di classi che implementano l'interfaccia Serializable.
Attraverso l'implementazione dell'interfaccia Serializable una classe diventa serializzabile.
Tuttavia, nessuna implementazione viene richiesta al programamtore
- Implementazione "fantasma";
Il comportamento ottenuto è quello descritto precedentemente (serializzazione standard).
class B implements Serializable { private static final long serialVersionUID = 1L; private int val; private A Aref; public B(int i, A ref) { val = i; Aref = ref; } public int getVal() {return val;} public A getA() {return Aref;} }
Vogliamo creare una sottoclasse di A in grado di codificare i valori degli attributi al momento
della serializzazione, utilizzando una chiave.
Il valore intero verrà codificato sommandogli l'hashCode associato alla chiave (CodificaVal() ).
La stringa verrà codificata "sommando a ogni carattere il carattere in analoga posizione nella
chaive:
- Se la stringa è più lunga della chiave, si concatena la chiave tante volte quanto necessario;
- Metodo codificaTxt
La classe Asicura:
- Estende la classe A;
- Aggiunge un attributo key: la chiave da usare per la codifica;
- Aggiunge i metodi:
◦ private int codificaVal();
◦ private String codificaTxt();
per ottenere i valori codificati degli attributi Val e txt usando la key;
◦ public void decode(String p);
per decodificare gli attributi val e txt usando p come chiave.
class ASicura extends A{ private String key; public ASicura(int i, String s, String p) { super(i, s); key = p; } private int codificaVal() { return(super.val + key.hashCode()); } private String codificaTxt() { char[] newTxt = super.txt.toCharArray(); char[] keyC = key.toCharArray(); for(int i=0; i<newTxt.length; i++) newTxt[i] = (char) (newTxt[i] + keyC[i%keyC.length]); return(new String(newTxt)); } public void decode(String p) { key = p; super.val = super.val - key.hashCode(); char[] newTxt = super.txt.toCharArray(); char[] keyC = key.toCharArray(); for(int i=0; i<newTxt.length; i++) newTxt[i] = (char) (newTxt[i] - keyC[i%keyC.length]); super.txt = new String(newTxt);
- Un'stanza di B: Serializzata entrmabe le istanze in un file passato come parametri. La classe
ASicura ha ridefinito l'operazione di serializzazione.
import java.io.*; … public class scriviSicuro { public static void main(String[] args) throws IOException { if (args.length != 2 ) { System.err.println("Uso scriviSicuro "); System.exit(-1); } A a1 = new ASicura(100, "prova a vedere se funziona", args[1]); B b1 = new B(10, a1); File f = new File(args[0]); if (f.exists()) f.delete(); f.createNewFile(); ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream(f)); out.writeObject(b1); out.close(); } } Esempio / Deserializza
Programma che ricostruisce la struttura, serializzata in precedenza:
- File passato come primo parametro;
- DEcodifica il contenuto di ASicura usando come chiave il secondo parametro;
- Stampa il valore deglia ttributi:
◦ Prima della decodifica;
◦ Dopo la decodifica;
import java.io.*;
public class leggiSicuro { public static void main(String[] args) throws IOException{ if (args.length != 2 ) { System.err.println("Uso: deserializza "); System.exit(-1); } File f = new File(args[0]); if (!f.exists()) { System.err.println("File " + args[0] + " inesistente"); System.exit(-1); } ObjectInputStream in = new ObjectInputStream( new FileInputStream(f)); … try { B ref = (B) in.readObject(); System.out.println("A.val = " + ref.getA().getVal()); System.out.println("A.txt = " + ref.getA().getTxt()); System.out.println("B.val = " + ref.getVal()); Asicura a = (ASicura)ref.getA(); System.out.println("Decodifico..."); a.decode(args[1]); System.out.println("A.val = " + ref.getA().getVal()); System.out.println("A.txt = " + ref.getA().getTxt()); System.out.println("B.val = " + ref.getVal()); in.close(); } catch (ClassNotFoundException e) { System.err.println("Errore di deserializzazione"); e.printStackTrace(); in.close(); System.exit(-1); } } }