1. Serializasiya nə üçün lazımdır
Təsəvvür edin ki, obyektiniz — tətildə özünüzlə apardığınız əşyalardır. Serializasiya — çamadanın bütün məzmununu yükə qoyula və ya poçtla göndərilə bilən xüsusi konteynerə “yığmaqdır”. Deserializasiya isə uyğun olaraq — həmin konteyneri açmaq və əşyaları ilkin halında geri almaqdır.
Əslində, serializasiya obyekti bayt axınına çevirir; bu axını fayla saxlamaq, şəbəkə ilə ötürmək və ya sadəcə yaddaşda saxlamaq olar. Deserializasiya əksini edir: obyekti bu axından bərpa edir. Tam sadələşdirsək, serializasiya — obyekti sonradan “əridib” geri almaq üçün onu “dondurmaq” kimidir.
Proqramın işə düşmələri arasında obyektlərin vəziyyətini saxlamaq
Ən çox rast gəlinən ssenarilərdən biri — proqramın vəziyyətini saxlamaqdır. Məsələn, sizdə istifadəçilərin siyahısı, oyunun nəticələri və ya tətbiqin tənzimləmələri var. Bunların hamısını elə obyektlər şəklində saxlamaq rahatdır. Məlumatların işə düşmələr arasında itməməsi üçün onlar fayla serializə olunur, növbəti işə düşmədə isə deserializasiya edilir.
Yaxşı nümunə — adi oyun seyvi. Oyunçu səviyyəni keçəndə onun proqresi “dondurulur” və serializasiya vasitəsilə fayla yazılır. Ertəsi gün o oyunu işə salır və proqres “əridilir”: fayldakı məlumatlar yenidən obyektlərə çevrilir və oyunçu qaldığı yerdən davam edir.
Gəlin belə sadə bir seyv yaradaq:
import java.io.*;
// Oyunçu sinfi Serializable olmalıdır
class Player implements Serializable {
String name;
int score;
Player(String name, int score) {
this.name = name;
this.score = score;
}
}
public class GameSaveExample {
public static void main(String[] args) throws Exception {
// Oyunçu obyektini yaradırıq
Player player = new Player("Ihor", 1500);
// --- Saxlama (serializasiya) ---
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("save.dat"))) {
out.writeObject(player);
System.out.println("Proqres saxlanıldı!");
}
// --- Yükləmə (deserializasiya) ---
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("save.dat"))) {
Player loaded = (Player) in.readObject();
System.out.println("Proqres yükləndi: " + loaded.name + " xalı " + loaded.score);
}
}
}
Diqqət yetirin: bu kodun işləməsi üçün Player sinfi Serializable interfeysini həyata keçirməlidir. Bu barədə daha ətraflı — növbəti dərsdə!
- Player — ad və xal sahələri olan adi sinifdir, Serializable interfeysi ilə işarələnib (implements Serializable).
- ObjectOutputStream obyekti "save.dat" faylına yazır.
- ObjectInputStream eyni obyekti geri oxuyur.
- Nəticədə bizdə həqiqi seyv alınır: növbəti işə düşmədə proqram oyunçu obyektini eyni vəziyyətdə yükləyəcək.
Obyektlərin şəbəkə ilə və JVM-lər arasında ötürülməsi
Paylanmış sistemlərdə tez-tez obyektləri müxtəlif proqramlar və hətta müxtəlif maşınlar arasında ötürmək lazım olur. Məsələn, sizdə mesaj mübadiləsi aparmalı olan müştəri və server var. Serializasiya obyektin bir tərəfdə “qablaşdırılmasına”, şəbəkə ilə göndərilməsinə və digər tərəfdə “açılmasına” imkan verir.
Nümunə: Müştəri serverə sifariş obyektini (Order) göndərir, server onu qəbul edir, deserializasiya edir və emal edir.
Java texnologiyalarında istifadə
- RMI (Remote Method Invocation): uzaq obyektlərin metodlarını çağırmağa imkan verir — arqumentlərin və qaytarılan dəyərlərin ötürülməsi üçün serializasiya lazımdır.
- HTTP sessiyaları: servlet-lərdə sessiyadakı obyektlər konteyner yenidən işə salınanda serializə olunur.
- JMS (Java Message Service): komponentlər arasında mesajlar serializə oluna bilər.
- Keşləmə: obyektlər keşdə saxlamaq üçün (diskə və ya paylanmış saxlanmada) serializə oluna bilər.
Keşləmə və daşınma qabiliyyəti
Əgər aralıq nəticələri tez saxlamaq istəyirsinizsə (məsələn, keşləmə üçün), serializasiya əla alətdir. Obyekti serializasiya edir, onu diskdə və ya yaddaşda saxlayır, sonra isə təkrar hesablamalara ehtiyac olmadan sürətlə bərpa edirsiniz.
2. Serializasiyanın istifadə ssenarilərinə nümunələr
İstifadəçilər kolleksiyasını fayla saxlamaq
Tutaq ki, sizdə User sinfi var:
public class User {
String name;
int age;
// ... digər sahələr
}
Və sizdə istifadəçilərin siyahısı var:
List<User> users = new ArrayList<>();
users.add(new User("Vasya", 25));
users.add(new User("Masha", 30));
// ... və sairə
Bu siyahını fayla saxlamaq üçün onu serializasiya edirsiniz. Lazım olduqda — deserializasiya edir və eyni istifadəçilərlə eyni siyahını əldə edirsiniz. Xatırladaq ki, User sinfi (və onun bütün sahələri) serializasiyanı dəstəkləməlidir, yəni Serializable həyata keçirməlidir.
Müştəri ilə server arasında mesaj ötürülməsi
Klassik nümunə — çat. İstifadəçi mesaj yazır, Message obyekti serializə olunur və şəbəkə ilə göndərilir. Server bayt axınını qəbul edir, obyekti deserializasiya edir, emal edir və bəlkə də daha da ötürür.
import java.io.*;
import java.net.*;
// Mesaj Serializable olmalıdır
class Message implements Serializable {
String text;
Message(String text) {
this.text = text;
}
}
// Server
class Server {
public static void main(String[] args) throws Exception {
try (ServerSocket serverSocket = new ServerSocket(5000)) {
System.out.println("Server qoşulmanı gözləyir...");
Socket socket = serverSocket.accept();
System.out.println("Müştəri qoşuldu!");
try (ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) {
Message msg = (Message) in.readObject();
System.out.println("Mesaj alındı: " + msg.text);
}
}
}
}
// Müştəri
class Client {
public static void main(String[] args) throws Exception {
try (Socket socket = new Socket("localhost", 5000)) {
try (ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream())) {
Message msg = new Message("Salam, server!");
out.writeObject(msg);
System.out.println("Mesaj göndərildi!");
}
}
}
}
Bu necə işləyir:
- Əvvəlcə Server işə salınır (o, qoşulmanı gözləyir).
- Sonra Client işə salınır (o, "localhost:5000" ünvanına qoşulur).
- Müştəri Message obyektini serializasiya edir və onu soket vasitəsilə göndərir.
- Server bayt axınını qəbul edir, deserializasiya edir və mətni çap edir.
Burada biz soketlərdən (ServerSocket, Socket) istifadə edirik — bu, şəbəkə qarşılıqlı əlaqəsi mexanizmidir və siz bunu sonra öyrənəcəksiniz. Hazırda vacib olan şəbəkənin detalları deyil, ideyanın özüdür: müştəri Message obyektini yaradır, serializasiya edir və göndərir; server bayt axınını alır, onu yenidən obyektə deserializasiya edir və mesajı çap edir. Beləliklə, hələ ServerSocket və Socket siniflərinin nə olduğu aydın olmasa belə, nümunə serializasiyanın dəyərini göstərir: onun sayəsində obyekti “qablaşdırmaq”, şəbəkə ilə ötürmək və qarşı tərəfdə əlavə çevirmələr olmadan açmaq mümkündür.
Obyektlərin keşlənməsi
Böyük tətbiqlərdə işi sürətləndirmək üçün tez-tez keşləmə istifadə olunur. Məsələn, mürəkkəb hesablamaların nəticələri serializə olunaraq keşdə (faylda, verilənlər bazasında, paylanmış saxlanmada) saxlanılır. Növbəti sorğuda nəticəni obyekti deserializasiya edərək tez bərpa etmək olar.
import java.io.*;
// Keşləmək istədiyimiz hesablamanın nəticəsi
class Result implements Serializable {
int value;
Result(int value) {
this.value = value;
}
}
public class CacheExample {
private static final String CACHE_FILE = "cache.dat";
public static void main(String[] args) throws Exception {
Result result;
// Keşin olub-olmadığını yoxlayırıq
File file = new File(CACHE_FILE);
if (file.exists()) {
// Nəticəni keşdən yükləyirik
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) {
result = (Result) in.readObject();
System.out.println("Keşdən yükləndi: " + result.value);
}
} else {
// "Ağır" hesablamalar (nümunə üçün sadəcə ədədin kvadratı)
int x = 12345;
System.out.println("Hesablayırıq... (bu vaxt aparır)");
result = new Result(x * x);
// Nəticəni keşe saxlayırıq
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) {
out.writeObject(result);
System.out.println("Keşdə saxlanıldı: " + result.value);
}
}
}
}
3. Serializasiyanın məhdudiyyətləri və riskləri
Serializasiya güclü alətdir, amma bəzi “gizli daşları” var. Gəlin əsas məhdudiyyət və riskləri müzakirə edək.
Bütün obyektləri serializə etmək olmur
Java-da bütün obyektlər “qutudan çıxan kimi” serializə edilə bilmir. Məsələn, xarici resurslarla (fayllar, şəbəkə bağlantıları, giriş-çıxış axınları) bağlı obyektlər serializasiyaya yararlı deyil. Bu məntiqlidir: “açıq faylı” və ya “canlı” şəbəkə bağlantısını serializasiya etmək mümkün deyil — onların vəziyyəti əməliyyat sistemindən və icra mühitindən asılıdır.
Nümunə: FileInputStream tipli sahəsi olan sinfi serializasiya etmək olmaz — serializasiya cəhdində xəta yaranacaq.
Təhlükəsizlik məsələləri
Serializasiya potensial təhlükəsizlik boşluğudur. Əgər etibarsız mənbədən (məsələn, internetdən) əldə edilən məlumatları deserializasiya etsəniz, təcavüzkar proqramınızın gözlənilməz davranışına və hətta zərərli kodun icrasına səbəb ola biləcək zərərli bayt axını “qoya” bilər.
Qayda: Heç vaxt etibarsız mənbələrdən gələn məlumatları deserializasiya etməyin! Bu, naməlum göndəricidən bağlama qəbul etməyə bənzəyir — içindən nə çıxacağı bilinmir.
Versiya uyğunluğu
Əgər sinfin strukturunu dəyişsəniz (məsələn, sahə əlavə edib və ya silsəniz), əvvəllər serializə edilmiş obyektlər sinfin yeni versiyası ilə uyğunsuz ola bilər. Bu, deserializasiya zamanı xətalara səbəb ola bilər. Bu məsələyə daha ətraflı növbəti dərslərdə baxacağıq.
Performans
Java-da binar serializasiya kifayət qədər sürətlidir, lakin bəzən ən kompakt deyil və digər proqramlaşdırma dilləri ilə mübadilə üçün hər zaman rahat olmur. Xarici sistemlərlə mübadilə üçün çox vaxt mətn formatlarından (JSON, XML) istifadə olunur.
4. Serializasiya ilə ilk tanışlıqda tipik səhvlər
Səhv №1: Serializable interfeysini həyata keçirməyən obyektin serializasiyasına cəhd.
Nəticədə NotSerializableException istisnası alacaqsınız. Sinifdə açıq şəkildə implements Serializable göstərməyi və bütün sahələrin də serializasiya oluna bilməsinə nəzarət etməyi unutmayın!
Səhv №2: serializasiya oluna bilməyən sahələri olan obyektlərin serializasiyası.
Əgər sinfiniz serializasiyanı dəstəkləməyən tipli sahə saxlayırsa (məsələn, axın və ya DB bağlantısı), serializasiya işləməyəcək. Həll — belə sahələri transient kimi işarələmək (buna sonra baxacağıq).
Səhv №3: etibarsız mənbələrdən gələn məlumatların deserializasiyası.
Bu, təhlükəsizlik zəifliklərinə və hətta zərərli kodun icrasına gətirib çıxara bilər. Yalnız sizin proqramınız tərəfindən serializə edilmiş məlumatlara etibar edin!
Səhv №4: serializasiyadan sonra sinfin strukturunun dəyişdirilməsi.
Əgər obyekti saxladınız, sonra isə sinifdə sahə əlavə etdiniz və ya sildinizsə, deserializasiya zamanı xəta yarana bilər və ya “qəribə” dəyərlər görünə bilər. Ətraflı — növbəti dərslərdə.
GO TO FULL VERSION