1. Giriş
Java-da sərializasiya yalnız bunu açıq şəkildə icazə verən obyektlərlə işləyir. Bunun üçün sinif xüsusi interfeysi — java.io.Serializable — reallaşdırmalıdır.
import java.io.Serializable;
public class Person implements Serializable {
// Sahələr, konstruktorlar, metodlar
}
Serializable marker interfeysdir: onun metodları yoxdur, o sadəcə JVM-ə — «bu sinfi sərializasiya etmək olar, narahat olmayın!» — xəbər verir. Əgər Serializable reallaşdırmayan sinfin obyektini sərializasiya etməyə cəhd etsəniz, NotSerializableException alacaqsınız. Hətta ən azı bir sahə (və ya daxil edilmiş obyekt) sərializasiya oluna bilmirsə — sərializasiya işləməyəcək.
ObjectOutputStream və ObjectInputStream
- ObjectOutputStream — obyektləri axına yazan sinifdir (məsələn, fayla və ya şəbəkə üzərindən).
- ObjectInputStream — obyektləri axından oxuyan sinifdir.
Onlar cütlük kimi işləyir: biri obyekti sərializasiya edir, digəri — deserializasiya edir.
Əsas metodlar
- writeObject(Object obj) — obyekti sərializasiya edir və onu axına yazır.
- readObject() — obyekti axından oxuyur, deserializasiya edir və geri qaytarır.
Vacibdir: hər iki sinif adi giriş-çıxış axınlarının (OutputStream və InputStream) üzərində işləyir. Çox vaxt onları fayl axınları ilə — FileOutputStream və FileInputStream — birlikdə istifadə edirlər, lakin şəbəkə axınları ilə də tətbiq etmək olar.
2. Sərializasiya nümunəsi
Gəlin sadə bir nümunə yazaq: Person sinfinin obyektini sərializasiya edib deserializasiya edək.
Addım 1. Sinfi təsvir edirik
import java.io.Serializable;
public class Person implements Serializable {
private String name;
private int age;
// transient sahə sərializasiya olunmayacaq
private transient String secret;
public Person(String name, int age, String secret) {
this.name = name;
this.age = age;
this.secret = secret;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + ", secret='" + secret + "'}";
}
}
Addım 2. Obyektin fayla sərializasiyası
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class SerializeDemo {
public static void main(String[] args) throws Exception {
Person person = new Person("Alice", 30, "likes pizza");
// Fayla yazmaq üçün axın yaradırıq
FileOutputStream fileOut = new FileOutputStream("person.bin");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
// Obyekti saxlayırıq
out.writeObject(person);
// Axınları bağlayırıq
out.close();
fileOut.close();
System.out.println("Obyekt person.bin faylına sərializasiya olundu");
}
}
Addım 3. Obyektin fayldan deserializasiyası
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class DeserializeDemo {
public static void main(String[] args) throws Exception {
// Fayldan oxumaq üçün axını açırıq
FileInputStream fileIn = new FileInputStream("person.bin");
ObjectInputStream in = new ObjectInputStream(fileIn);
// Obyekti bərpa edirik
Person person = (Person) in.readObject();
in.close();
fileIn.close();
System.out.println("Obyekt deserializasiya olundu: " + person);
}
}
Gözlənilən çıxış
Obyekt person.bin faylına sərializasiya olundu
Obyekt deserializasiya olundu: Person{name='Alice', age=30, secret='null'}
Diqqət! transient sahə sərializasiya olunmur. Deserializasiyadan sonra onun dəyəri null olacaq. Bu, müvəqqəti və ya həssas məlumatlar üçün vacibdir.
3. Məhdudiyyətlər və özəlliklər
Bütün sahələr sərializasiya oluna bilən olmalıdır
Əgər sinifdə Serializable reallaşdırmayan sahələr (və ya belə obyektlər saxlayan sahələr) varsa, sərializasiya xəta ilə tamamlanacaq. Məsələn, Thread və ya Socket kimi tipləri «elə-belə» sərializasiya oluna bilən etmək mümkün deyil.
Statik və transient sahələr
- Statik sahələr (static) sərializasiya olunmur: onlar konkret obyektə yox, sinifə məxsusdur.
- transient sahələr — transient kimi işarələnmiş sahələr sərializasiyadan məqsədli şəkildə çıxarılır və bərpadan sonra standart dəyərləri alır (null, 0 və s.).
İstisnalar
- Serializable reallaşdırmayan obyekti sərializasiya etmək cəhdi NotSerializableException yaradır.
- Deserializasiya zamanı mümkün xətalar: fayl tapılmadı, siniflər uyğun gəlmir, məlumatlar zədələnib və s.
Siniflərin versiyaları
Əgər sərializasiyadan sonra sinifin strukturunu dəyişsəniz (məsələn, sahə əlavə/çıxarsanız), deserializasiya zamanı InvalidClassException yarana bilər. Versiyaya nəzarət üçün xüsusi serialVersionUID sahəsindən istifadə olunur (bu haqda növbəti mühazirələrdən birində daha ətraflı).
4. Təcrübə: obyektin fayla sərializasiyası və fayldan deserializasiyası
Tutaq ki, bizdə Person sinfi var və insanlar siyahısını fayla saxlamaq, sonra isə geri oxumaq istəyirik.
Person sinfi (sərializasiya oluna bilən)
import java.io.Serializable;
public class Person implements Serializable {
private String name;
private int age;
private transient String secret; // sərializasiya olunmayacaq
public Person(String name, int age, String secret) {
this.name = name;
this.age = age;
this.secret = secret;
}
@Override
public String toString() {
return name + " (" + age + "), secret: " + secret;
}
}
İnsanlar siyahısının sərializasiyası
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
public class SerializeListDemo {
public static void main(String[] args) throws Exception {
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30, "likes pizza"));
people.add(new Person("Bob", 25, "hates broccoli"));
FileOutputStream fileOut = new FileOutputStream("people.bin");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
// Siyahını saxlayırıq
out.writeObject(people);
out.close();
fileOut.close();
System.out.println("İnsanlar siyahısı sərializasiya olundu.");
}
}
İnsanlar siyahısının deserializasiyası
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.List;
public class DeserializeListDemo {
public static void main(String[] args) throws Exception {
FileInputStream fileIn = new FileInputStream("people.bin");
ObjectInputStream in = new ObjectInputStream(fileIn);
// Siyahını bərpa edirik
List<Person> people = (List<Person>) in.readObject();
in.close();
fileIn.close();
for (Person p : people) {
System.out.println(p);
}
}
}
Nəticə:
Alice (30), secret: null
Bob (25), secret: null
5. Tipik səhvlər
Səhv №1: Sinif Serializable reallaşdırmır. Əgər implements Serializable əlavə etməyi unutsanız, sərializasiya zamanı NotSerializableException alacaqsınız. Bu, ən yayılmış və ən sadə səhvdir.
Səhv №2: Sərializasiya olunmayan sahə. Əgər obyekt sərializasiya oluna bilməyən bir sahə saxlayırsa (məsələn, Thread, Socket və ya Serializable olmayan istənilən başqa tip), sərializasiya «yıxılacaq». Belə sahələri transient kimi işarələyin və ya onları sərializasiya oluna bilən edin.
Səhv №3: Sinifin strukturunun dəyişdirilməsi. Əgər obyekt sərializasiya olunub, sonra isə sinif dəyişdirilibsə (sahələr əlavə/çıxarılıbsa), oxuma zamanı InvalidClassException mümkündür. Versiya sabitliyinə nəzarət üçün serialVersionUID göstərin.
Səhv №4: Statik sahələri sərializasiya etməyə cəhd. static modifikatorlu sahələr sərializasiya olunmur. Deserializasiyadan sonra onların dəyərləri, sərializasiya anındakı yox, sinifdəki standart dəyərlər olacaq.
Səhv №5: Axınlar bağlanmayıb. İşdən sonra axınları bağlamasanız, fayl zədələnə və ya resurs sızması yarana bilər. try-with-resources istifadə edin və ya axınları açıq şəkildə bağlayın.
Səhv №6: Siniflərin uyğun gəlməməsi. Əgər sinfin adı dəyişdirilibsə və ya başqa paketə köçürülübsə, deserializasiya işləməyəcək — axında saxlanmış sinfin adı və paketi ilə tam uyğunluq tələb olunur.
GO TO FULL VERSION