Serializarea
Serializarea reprezintă procesul de scriere a stării unui obiect într-un flux. Procesul de extragere sau restaurare a stării obiectului din flux se numește deserializare. Serializarea este foarte utilă atunci când lucrăm cu obiecte complexe.
Interfața Serializable.
Numai obiectele care implementează interfața Serializable pot fi serializate. Această interfață nu definește metode, ci doar semnalează sistemului că obiectele care o implementează pot fi serializate.
Serializarea - Clasa ObjectOutputStream
Clasa ObjectOutputStream este utilizată pentru a serializa obiectele într-un flux. Ea scrie datele în fluxul de ieșire.
Constructor pentru ObjectOutputStream:
ObjectOutputStream(OutputStream out)
Pentru înregistrarea datelor, ObjectOutputStream utilizează o serie de metode, printre care se pot distinge următoarele:
- void close(): închide fluxul
- void flush(): golește buffer-ul și transferă conținutul său în fluxul de ieșire
- void write(byte[] buf): scrie în flux un array de bytes
- void write(int val): scrie în flux un byte inferior din val
- void writeBoolean(boolean val): scrie în flux valoarea boolean
- void writeByte(int val): scrie în flux un byte inferior din val
- void writeChar(int val): scrie în flux valoarea de tip char, reprezentată printr-o valoare întreagă
- void writeDouble(double val): scrie în flux valoarea de tip double
- void writeFloat(float val): scrie în flux valoarea de tip float
- void writeInt(int val): scrie valoarea întreagă int
- void writeLong(long val): scrie valoarea de tip long
- void writeShort(int val): scrie valoarea de tip short
- void writeUTF(String str): scrie în flux un string în codarea UTF-8
- void writeObject(Object obj): scrie în flux un obiect separat
Aceste metode acoperă întreaga gamă de date care pot fi serializate.
De exemplu, salvăm într-un fișier un obiect al clasei Person:
import java.io.*;
public class Program {
public static void main(String[] args) {
try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.dat")))
{
Person p = new Person("Sam", 33, 178, true);
oos.writeObject(p);
}
catch(Exception ex){
System.out.println(ex.getMessage());
}
}
}
class Person implements Serializable{
private String name;
private int age;
private double height;
private boolean married;
Person(String n, int a, double h, boolean m){
name=n;
age=a;
height=h;
married=m;
}
String getName() {return name;}
int getAge(){ return age;}
double getHeight(){return height;}
boolean getMarried(){return married;}
}
Deserializare - Clasa ObjectInputStream
Clasa ObjectInputStream este responsabilă pentru procesul invers - citirea datelor serializate anterior din flux. În constructor, primește o referință la fluxul de intrare:
ObjectInputStream(InputStream in)
Funcționalitatea ObjectInputStream este concentrată în metode destinate citirii diferitelor tipuri de date. Iată principalele metode ale acestei clase:
- void close(): închide fluxul
- int skipBytes(int len): sare peste un număr de bytes la citire, egal cu len
- int available(): returnează numărul de bytes disponibili pentru citire
- int read(): citește din flux un byte și returnează reprezentarea sa întreagă
- boolean readBoolean(): citește din flux o valoare boolean
- byte readByte(): citește din flux un byte
- char readChar(): citește din flux un caracter char
- double readDouble(): citește valoarea de tip double
- float readFloat(): citește din flux valoarea de tip float
- int readInt(): citește valoarea întreagă int
- long readLong(): citește valoarea de tip long
- short readShort(): citește valoarea de tip short
- String readUTF(): citește un string în codarea UTF-8
- Object readObject(): citește din flux un obiect
De exemplu, extragem obiectul Person salvat mai devreme din fișier:
import java.io.*;
public class Program {
public static void main(String[] args) {
try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.dat")))
{
Person p=(Person)ois.readObject();
System.out.printf("Name: %s \t Age: %d \n", p.getName(), p.getAge());
}
catch(Exception ex){
System.out.println(ex.getMessage());
}
}
}
Acum combinăm salvarea și restaurarea din fișier pe un exemplu de listă de obiecte:
import java.io.*;
import java.util.ArrayList;
public class Program {
//@SuppressWarnings("unchecked")
public static void main(String[] args) {
String filename = "people.dat";
// creăm o listă de obiecte pe care o vom scrie
ArrayList<Person> people = new ArrayList<Person>();
people.add(new Person("Tom", 30, 175, false));
people.add(new Person("Sam", 33, 178, true));
try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename)))
{
oos.writeObject(people);
System.out.println("File has been written");
}
catch(Exception ex){
System.out.println(ex.getMessage());
}
// deserializare într-o nouă listă
ArrayList<Person> newPeople= new ArrayList<Person>();
try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename)))
{
newPeople=((ArrayList<Person>)ois.readObject());
}
catch(Exception ex){
System.out.println(ex.getMessage());
}
for(Person p : newPeople)
System.out.printf("Name: %s \t Age: %d \n", p.getName(), p.getAge());
}
}
class Person implements Serializable{
private String name;
private int age;
private double height;
private boolean married;
Person(String n, int a, double h, boolean m){
name=n;
age=a;
height=h;
married=m;
}
String getName() {return name;}
int getAge(){ return age;}
double getHeight(){return height;}
boolean getMarried(){return married;}
}
Excluderea datelor din serializare
Implicit, toate variabilele obiectului sunt serializate. Cu toate acestea, este posibil să dorim să excludem unele câmpuri din serializare. Pentru aceasta, ele trebuie declarate cu modificatorul transient. De exemplu, excludem din serializarea obiectului Person variabilele height și married:
class Person implements Serializable{
private String name;
private int age;
private transient double height;
private transient boolean married;
Person(String n, int a, double h, boolean m){
name=n;
age=a;
height=h;
married=m;
}
String getName() {return name;}
int getAge(){ return age;}
double getHeight(){return height;}
boolean getMarried(){return married;}
}