CodeGym /Kurslar /JAVA 25 SELF /Serializable interfeysi: əsas prinsiplər

Serializable interfeysi: əsas prinsiplər

JAVA 25 SELF
Səviyyə, Dərs
Mövcuddur

1. Serializable interfeysi

Ötən mühazirədəki nümunələri xatırlayırsınız? Serializasiya etmək istədiyimiz Java sinifləri xüsusi interfeysi — java.io.Serializable — reallaşdırmalıdır. Bu, marker interfeys adlanır: o, heç bir metod ehtiva etmir və sadəcə sinfi serializasiya üçün uyğun olaraq “işarələyir”. Sinif bu interfeysi reallaşdırırsa, JVM onun obyektlərini standart vasitələrlə serializə etməyə icazə verir.

Hər şeyi serializasiya etmək məsləhət deyil, çünki bütün obyektləri baytlara çevirmək mümkün və ya lazım deyil. Bəzi obyektlər əməliyyat sisteminin vəziyyətindən, açıq fayllardan və ya şəbəkə bağlantılarından asılıdır. Buna görə Java sinfi açıq şəkildə serializasiya olunan kimi işarələməyi tələb edir.

Marker interfeys — qutunun üzərindəki “qablaşdırmağa icazə verilir” etiketinə bənzəyir. Belə etiket yoxdursa — “qablaşdıran” (JVM) işləməkdən imtina edir.

Nümunə: serializasiya olunan sinfin elan edilməsi

import java.io.Serializable;

public class User implements Serializable {
    private String name;
    private int age;

    // Konstruktor, getter və setterlər
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Gözəllik üçün: toString() metodu
    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + "}";
    }
}

Nəzərə alın:

  • Sadəcə sinifin elanına implements Serializable əlavə etdik.
  • Heç bir metodu reallaşdırmağa ehtiyac yoxdur (interfeys boşdur).
  • Serializasiya oluna bilən bütün standart Java sinifləri (məsələn, ArrayList, HashMap, String) artıq Serializable-ı reallaşdırır.

2. Öz sinfinizi serializasiya oluna bilən etmək

Qayda № 1: Sadəcə implements Serializable əlavə edin

Sinfin özünə lazım olan budur. Amma nüanslar var!

Vacibdir: istinad olunan bütün obyektlər də serializasiya oluna bilən olmalıdır.
Sinifinizin digər obyektlərə istinad edən sahələri varsa, onlar da serializasiya oluna bilən olmalıdır. Məsələn:

public class Profile implements Serializable {
    private User user; // User serializasiya edilə bilən olmalıdır!
    private int level;
}

Sahələrdən ən azı biri serializasiya oluna bilmirsə, serializasiya cəhdi zamanı istisna atılacaq.

3. Serializasiya və deserializasiya nümunəsi

Gəlin obyektin fayla necə serializasiya edilib fayldan necə deserializasiya olunduğuna baxaq. Bunun üçün ObjectOutputStream və ObjectInputStream siniflərindən istifadə olunur.

Nümunə: obyekt User-in fayla serializasiyası

import java.io.*;

public class SerializeDemo {
    public static void main(String[] args) {
        User user = new User("Alice", 30);

        // Obyekti fayla yazırıq
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.ser"))) {
            oos.writeObject(user);
            System.out.println("Obyekt uğurla user.ser faylına serializasiya olundu");
        } catch (IOException e) {
            System.out.println("Serializasiya xətası: " + e.getMessage());
        }
    }
}

Burada nə baş verir?

  • User obyekti yaradırıq.
  • ObjectOutputStream axınını açırıq, o isə "user.ser" faylına yazır.
  • writeObject(user) çağırırıq. Bu an JVM obyekti bayt axınına çevirir və fayla saxlayır.

Nümunə: obyektin fayldan deserializasiyası

import java.io.*;

public class DeserializeDemo {
    public static void main(String[] args) {
        // Obyekti fayldan oxuyuruq
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.ser"))) {
            User user = (User) ois.readObject();
            System.out.println("Obyekt uğurla bərpa olundu: " + user);
        } catch (IOException | ClassNotFoundException e) {
            System.out.println("Deserializasiya xətası: " + e.getMessage());
        }
    }
}

Burada nə baş verir?

  • ObjectInputStream axınını açırıq, o isə "user.ser" faylından oxuyur.
  • readObject() çağırırıq. JVM obyekti baytlardan bərpa edir.
  • Nəticəni lazımi tipə (User) çevirməyi unutmayın, çünki readObject() Object qaytarır.
  • Deserializasiya zamanı ClassNotFoundException yarana bilər, əgər User sinfi tapılmasa.

Hamısı birlikdə: serializasiya və deserializasiya

import java.io.*;

public class SerializationExample {
    public static void main(String[] args) {
        User user = new User("Bob", 22);

        // Serializasiya
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.ser"))) {
            oos.writeObject(user);
            System.out.println("Serializasiya başa çatdı!");
        } catch (IOException e) {
            System.out.println("Serializasiya xətası: " + e.getMessage());
        }

        // Deserializasiya
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.ser"))) {
            User loaded = (User) ois.readObject();
            System.out.println("Deserializasiya başa çatdı! " + loaded);
        } catch (IOException | ClassNotFoundException e) {
            System.out.println("Deserializasiya xətası: " + e.getMessage());
        }
    }
}

Nəticə:

Serializasiya başa çatdı!
Deserializasiya başa çatdı! User{name='Bob', age=22}

4. Serializasiya zamanı “kapotun altında” nə baş verir

writeObject çağırdığınızda, JVM əvvəlcə sinfin Serializable interfeysini reallaşdırıb-reallaşdırmadığını yoxlayır. Əgər sinif serializasiya olunan kimi işarələnməyibsə, istisna atılır. Sonra JVM obyektin bütün adi sahələrindən (yəni static və transient olmayanlardan) keçərək onların dəyərlərini bayt axınına yazır. Bu sahələr arasında başqa obyektlər varsa, onlar da rekursiv şəkildə serializasiya olunur, ancaq yalnız onlar da Serializable-ı reallaşdırırsa.

Deserializasiya zamanı obyekt adi konstruktor çağırılmadan yaradılır və onun sahələri saxlanmış dəyərlərlə doldurulur — sanki “konstruktorsuz konstruktor” obyekti bayt axınından canlandırır.

Bəzi sahələr serializasiya olunmur. Statik sahələr (static) obyektə deyil, sinfin özünə məxsusdur, buna görə onların dəyərləri saxlanmır. transient kimi işarələnmiş sahələr də ötürülür — bu, müvəqqəti məlumatlar, keş və ya şifrələr kimi məxfi informasiya üçün əlverişlidir.

Serializasiya prosesinin sxemi

flowchart TB
    A[Obyekt User yaddaşda] -- writeObject --> B[ObjectOutputStream]
    B -- baytları saxlayır --> C[Fayl user.ser]
    C -- readObject --> D[ObjectInputStream]
    D -- bərpa edir --> E[Obyekt User yaddaşda]

5. Serializable istifadə edərkən tipik səhvlər

Səhv № 1: Serializasiya olunmayan obyektə istinad edən sahə. Əgər User sinfində, məsələn, Thread və ya Socket tipində sahə peyda olarsa, serializasiya işləməyəcək. Bütün obyektləri serializasiya etmək olmur — bunu yadda saxlayın!

Səhv № 2: Serializasiya olunmayan daxili siniflər. Əgər User sinfi static olmayan daxili sinif saxlayırsa, serializasiya işləməyə bilər. Daha yaxşısı static daxili siniflərdən və ya ayrıca sinif fayllarından istifadə etməkdir.

Səhv № 3: static sahəni serializasiya etməyə cəhd. Statik sahələr serializasiya olunmur — onlar sinfə məxsusdur, obyektə yox. Deserializasiyadan sonra static sahənin dəyəri serializə olunmuş obyektin deyil, sinifdə müəyyən edilmiş dəyər olacaq.

Səhv № 4: Sinif versiyalarının uyğunsuzluğu. Əgər serializasiyadan sonra sinfin strukturunu dəyişsəniz (məsələn, sahə əlavə və ya silsəniz) və sonra köhnə obyekti deserializasiya etməyə çalışsanız, InvalidClassException xətası yarana bilər. Versiyalara nəzarət üçün xüsusi serialVersionUID sahəsindən istifadə olunur — bunun haqqında növbəti mühazirədə daha ətraflı danışacağıq.

1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Marker interfeysi Serializable
Marker interfeysi Serializable
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Sadə seriyalaşdırma və deserializasiya
Sadə seriyalaşdırma və deserializasiya
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION