Serializarea obiectelor
Serializarea obiectelor
Serializarea este o metodă prin care se pot salva, într-o manieră unitară, datele împreună cu signatura unui
obiect. Folosind această operaţie se poate salva într-un fişier, ca şir de octeţi, o instanţă a unei clase, în orice
moment al execuţiei. De asemenea, obiectul poate fi restaurat din fişierul în care a fost salvat în urma unei
operaţii de serializare.
Salvarea datelor înapsulate într-un obiect se poate face şi prin salvarea pe rând a datelor, folosind clasa
DataOutputStream, pentru ca apoi să fie restaurate prin metode ale clasei DataInputStream, dar o asemenea
abordare nu este în general suficientă, deoarece pot apărea probleme cum ar fi :
datele obiectului pot fi instanţe ale altor obiecte
în unele cazuri, este necesară şi salvarea tipului datei
unele câmpuri fac referinţă la acelaşi obiect
Aşadar, prin serializare sunt surprinse atât datele, signatura clasei (numele metodelor şi definiţia lor - nu
şi implementarea) precum şi starea obiectului.
Pentru a putea fi serializat un obiect trebuie să fie instanţă a unei clase care implementează una din
interfeţele :
- [Link] sau
- [Link] (care extinde clasa Serializable)
Interfaţa Serialize nu are nici o metodă, ea dă doar posibilitatea de a specifica faptul că se doreşte ca o anumită
clasă să poată fi serializată. Declaraţia unei astfel de clase ar fi :
class ClasaSerializabila implements Serializable {...}
In urma serializării obiectele sunt pot fi salvatr într-un fişier, în acelaşi fişier putând fi salvate şi mai multe obiecte.
Operaţiile de intrare ieşire la nivelul obicetelor se realizează prin intermediul unor fluxuri de obiecte, implementate
de clasele ObjectInputStream şi ObjectOutputStream.
Salvarea unui obiect într-un fişier se realizează astfel :
MyObject o = new MyObject();
FileOutputStream fout = new FileOutputStream(“fisier”);
ObjectOutputStream sout = new ObjectOutputStream(fout);
[Link](o);
Restaurarea unui obiect salvat într-un fişier se face într-o manieră asemănătoare:
FileInputStream fin = new FileInputStream(“fisier”);
ObjectInputStream sin = new ObjectInputStream(fin);
o = (MyObject) [Link]();
Pe lângă metodele de scriere/citire a obiectelor cele două clase pun la dispoziţie şi metode pentru scrierea
tipurilor de date primare, astfel încât apeluri ca cele de mai jos sunt permise :
FileOutputStream ostream = new FileOutputStream("[Link]");
ObjectOutputStream p = new ObjectOutputStream(ostream);
[Link](12345);
[Link]("Today");
[Link](new Date());
[Link]();
[Link]();
FileInputStream istream = new FileInputStream("[Link]");
ObjectInputStream p = new ObjectInputStream(istream);
int i = [Link]();
String today = (String)[Link]();
Date date = (Date)[Link]();
1
Serializarea obiectelor
[Link]();
ObjectInputStream şi ObjectOutputStream implementează indirect interfeţele DataInput, respectiv DataOutput,
interefţe ce declară metode atât pentru scrierea/citirea datelor primitive, cât şi pentru scrierea/citirea obiectelor.
Pentru transferul obiectelor sunt folosite metodele:
final void writeObject( [Link] obj )
throws [Link]
final [Link] readObject( )
throws [Link], [Link], [Link]
Acestea apelează la rândul lor metodele implicte de transfer defaultWriteObject şi defaultReadObject (având
aceleaşi signaturi ca mai sus)
Clasa ObjectOutputStream
Constructor
public ObjectOutputStream( [Link] out )
throws [Link]
Metode
void close( ) throws [Link]
final void defaultWriteObject( ) throws [Link]
void flush( ) throws [Link]
void reset( ) throws [Link]
void write( byte[] b ) throws [Link]
void write( byte[] b, int off, int len ) throws [Link]
void write( int data ) throws [Link]
void writeBoolean( boolean data ) throws [Link]
void writeByte( int data ) throws [Link]
void writeBytes( [Link] data ) throws [Link]
void writeChar( int data ) throws [Link]
void writeChars( [Link] data ) throws [Link]
void writeDouble( double data ) throws [Link]
void writeFloat( float data ) throws [Link]
void writeInt( int data ) throws [Link]
void writeLong( long data ) throws [Link]
final void writeObject( [Link] obj )
throws [Link]
void writeShort( int data ) throws [Link]
void writeUTF( [Link] data ) throws [Link]
Clasa ObjectInputStream
Constructor
public ObjectInputStream( [Link] in )
throws [Link], [Link]
Create an ObjectInputStream that reads from the specified InputStream. The stream header containing the magic
number and version number are read from the stream and verified. This method will block until the corresponding
ObjectOutputStream has written and flushed the header.
2
Serializarea obiectelor
Metode
int available( ) throws [Link]
void close( ) throws [Link]
final void defaultReadObject( )
throws [Link], [Link], [Link]
int read( byte[] data, int offset, int length )
throws [Link]
int read( ) throws [Link]
boolean readBoolean( ) throws [Link]
byte readByte( ) throws [Link]
char readChar( ) throws [Link]
double readDouble( ) throws [Link]
float readFloat( ) throws [Link]
void readFully( byteşţ data ) throws [Link]
void readFully( byteşţ data, int offset, int size )
throws [Link]
int readInt( ) throws [Link]
[Link] readLine( ) throws [Link]
long readLong( ) throws [Link]
final [Link] readObject( )
throws [Link], [Link], [Link]
short readShort( ) throws [Link]
int readUnsignedByte( ) throws [Link]
int readUnsignedShort( ) throws [Link]
[Link] readUTF( ) throws [Link]
ynchronized void registerValidation( [Link] obj,
int prio )
throws [Link], [Link]
int skipBytes( int len ) throws [Link]
Cuvintul cheie transient
Pentru ca un anumit câmp să nu fie salvat în urma serializării, acesta trebuie declarat cu modificatorul
transient. Aceste câmpuri vor fi ignorate de metodele writeObject şi readObject.
Ex:
private transient x; ignorat la serializare
Exemplu:
import [Link].*;
public class TestSerial {
static MyObject obj;
public static void main(String args[]) {
obj = new MyObject(10,20);
try {
FileOutputStream fout = new
FileOutputStream("[Link]");
ObjectOutputStream sout = new
ObjectOutputStream(fout);
[Link](obj);
[Link]();
[Link]();
[Link]();
[Link]("A fost salvat obiectul " + obj);
}
3
Serializarea obiectelor
catch (IOException e) {}
[Link]("Restauram...");
try {
FileInputStream fin = new
FileInputStream("[Link]");
ObjectInputStream sin = new ObjectInputStream(fin);
try {
obj = (MyObject) [Link]();
}
catch (ClassNotFoundException e) {}
[Link]();
[Link]();
[Link]("A fost restaurat obiectul " + obj);
}
catch (IOException e) {}
}
}
class MyObject implements Serializable {
int x;
private transient int y;
public MyObject(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return new String("x=" + x + ", y="+y);
}
}
Rezultatul acestui program va fi :
A fost salvat obiectul x=10, y=20
Restauram...
A fost restaurat obiectul x=10, y=0
Obs. Atunci când o clasă serializabilă derivă dintr-o altă clasă, salvarea câmpurilor clasei părinte se va face
doar dacă şi aceasta este serializabilă. In caz contrar, subclasa trebuie să salveze explicit şi câmpurile moştenite.
Ex1:
class Parinte implements Serializable {
int x;
...
}
class Fiu extends Parinte implements Serializable {
int y;
...
}
La serializare se salvează atât x cât şi y.
Ex1:
class Parinte {
int x;
...
4
Serializarea obiectelor
}
class Fiu extends Parinte implements Serializable {
int y;
...
}
Serializarea nu decurge normal.
Folosirea serializării pentru copierea obiectelor
Se ştie că nu putem copia un obiect prin instrucţiunea de atribuire. O secvenţă de forma:
MyObject o1 = new MyObject(10, 20);
MyObject o2 = o1;
nu face decât să declare obiectul o2 ca fiind o referinţă la obiectul o1. Orice schimbare într-unul din cele două
obiecte se va reflecta şi în celălalt.
o1 o2
date
O posibilitate de a face o copie unui obiect este folosirea metodei clone() a clasei Object.
MyObject o1 = new MyObject(10, 20);
MyObject o2 = (MyObject) [Link]();
o1 o2
date date(copie)
referinţă
Conversia la clasa MyObject este necesară deoarece metoda clone() returnează un obiect de tip Object.
Deficienţa acestei metode este că nu funcţionează corect decât atunci când clasa clonată nu are câmpuri referinţă
către alte obiecte, obiectele referite nemaifiind copiate la rândul lor.
O metodă clone() care să realizeze o copie efectivă a unui obiect, împreună cu copierea tuturor obiectelor
referite de câmpurile acelui obiect poate fi implementată prin mecanismul serializării astfel :
public Object clone() {
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout);
[Link](this);
[Link]();
ByteArrayInputStream bin = new ByteArrayInputStream();
ObjectInputStream in = new ObjectInputStream(bin);
Object ret = [Link]();
[Link]();
return ret;
}
catch (Exception e) {
[Link](e);
return null;
}
5
Serializarea obiectelor
}