Fluxuri de obiecte

Fluxurile de obiecte sunt fluxuri de prelucrare care permit să se transmită obiecte. În acest scop, obiectele transmise trebuie să fie serializate,  înainte de a fi transmise, adică să fie puse sub forma unei serii de octeti, într-un format care să permită la destinație reconstituirea în memorie a obiectului respectiv. Astfel de obiecte se numesc serializabile.

Pe platforma Java 2, fluxurile de obiecte se realizează prin clasele java.io.ObjectOutputStream și java.io.ObjectInputStream. Obiectele transmise de aceste fluxuri trebuie sa implementeze interfața java.io.Serializable.
 

Interfața Serializable

Orice obiect care se transmite pe un flux trebuie să aparțină unei clase care implementează interfața java.io.Serializable. Aceasta inseamnă că trebuie îndeplinite următoarele condiții:
   - la declararea clasei respective, se pune clauza implements Serializable;
   - clasa trebuie să conțină un constructor fără argumente;
   - toate câmpurile obiectului trebuie să fie serializabile, adică fie să aparțina unor tipuri de date, primitive, fie unor clase care implementează interfața Serializable.

Interfața Serializable nu conține câmpuri sau metode. Clauza implements Serializable constituie doar o indicație pentru compilatorul Java să o pună sub forma serializabilă.
 
Dacă, la transmiterea obiectelor pe flux, se constată că unul din acestea nu este serializabil, se generează excepția NotSerializableException.

Clasele care necesită o manipulare specială la serializare sau deserializare trebuie să conțina metode cu signaturile următoare:
 private void writeObject(java.io.ObjectOutputStream out)
     throws IOException
 private void readObject(java.io.ObjectInputStream in)
     throws IOException, ClassNotFoundException;
O prezentare mai amplă a acestei interfețe se găsește în documentația Java API. 

Clasa ObjectOutputStream

Clasa java.io.ObjectOutputStream este clasa fluxurilor de prelucrare pentru obiecte, având rolul de a serializa obiectele care urmează să fie puse într-un flux de ieșire. Fluxurile de obiecte se conectează la ieșire la un alt flux, de preferință la un FileOutputStream, ByteArrayOutputStream sau PipedOutputStream, iar utilizarea lor este asemănătoare cu cea a fluxurilor de date (DataOutputStream). Într-un flux de obiecte se pot scrie atât obiecte serializate, cât și date primitive sau șiruri.
 
Clasa ObjectOutputStream conține toate metodele de scriere a datelor primitive și a șirurilor, care există și în clasele DataOutputStream și RandomAccessFile. În plus, ea conține metode necesare pentru scrierea în flux a obiectelor, cea mai frecvent folosită fiind următoarea:
  public final void writeObject(Object obj)throws IOException - scrie în fluxul de ieșire obiectul obj sub formă serializată;
Informații mult mai ample despre această clasă pot fi găsite în documentația Java API.

Clasa ObjectInputStream

Clasa java.io.ObjectInputStream servește pentru citirea (deserializarea) fluxurilor de obiecte care au fost scrise folosind clasa java.io.ObjectOutputStream. Intrarea unui ObjectInputStream este conectată la ieșirea unui alt flux de intrare, de preferință FileInputStream, ByteArrayInputStream sau PipedInputStream.
 
Clasa ObjectInputStream conține toate metodele de citire a datelor primitive și a șirurilor existente în clasa DataInputStream. În plus, ea conține metode necesare pentru citirea obiectelor serializate, dintre care cea mai frecvent folosită este
  public final Object readObject() throws OptionalDataException, ClassNotFoundException, IOException
Informații mai ample despre această clasă se găsesc în documentația Java API.
Exemplu
În fișierul FisierObiecte.java este dat un exemplu de aplicație, în care se testează clasele ObjectOutputStream și ObjectInputStream. 
În prima parte a metodei main(), se creează un fișier (Proba1.dat) în care se scriu atât obiecte (din clasele Persoana și Student), cât și date primitive, șiruri și tablouri. Pentru scrierea obiectelor și a tablourilor se folosește metoda void writeObject(Object obj), iar pentru datele primitive și pentru șiruri se folosesc metodele specifice pentru scrierea tipurilor respective. După ce s-a încheiat scrierea datelor, se închide fișierul Proba1.dat.
În partea a doua a metodei main() se deschide fișierul Proba1.dat pentru citire și se citesc din el toate datele scrise anterior, în ordinea în care au fost scrise. Întrucât metoda Object readObject() întoarce un Object, acesta este convertit prin cast într-un obiect din clasa căruia îi aparține în realitate.
În ultima parte a metodei main() se afișează pe ecran datele citite, putându-se astfel verifica faptul că serializarea și deserializarea s-au făcut corect.
Remarcăm că, în afară de date primitive și obiecte, au fost scrise în fișier (prin metoda writeObject) și tablouri unidimensionale și bidimensionale, care au fost apoi citite corect (prin metoda readObject).
Din acest exemplu se poate constata că clasele ObjectOutputStream și ObjectInputStream constituie un instrument foarte puternic de salvare și restaurare a datelor din memorie la nivelul obiectelor (al structurilor de date), care îl scutesc pe programator de munca laborioasă și dificilă se a programa aceste operații la nivelul inferior al fluxurilor de octeți sau la nivelul fluxurilor de date primitive.



© Copyright 2000 - Severin BUMBARU, Universitatea "Dunărea de Jos" din Galați