CodeGym /Kurslar /JAVA 25 SELF /Externalizable: seriyalaşdırmanın incə tənzimlənməsi

Externalizable: seriyalaşdırmanın incə tənzimlənməsi

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

1. Giriş

Java-da obyektlərin seriyalaşdırılması üçün ən çox Serializable interfeysindən istifadə olunur. O, sadədir: interfeysi reallaşdırmaq kifayətdir və obyekti ObjectOutputStream/ObjectInputStream vasitəsilə yazmaq/oxumaq olar. Lakin bəzən bu kifayət etmir:

  • Hansı sahələrin və necə seriyalaşdırılacağına tam nəzarət lazımdır.
  • Sinfin müxtəlif versiyaları arasında uyğunluq təmin edilməlidir.
  • Seriyalaşdırılmış faylın ölçüsünü azaltmaq və ya prosesi sürətləndirmək vacibdir.

Belə hallarda Java-da Externalizable interfeysi — daha «əl ilə» və çevik seriyalaşdırma üsuludur.

Qısaca:

  • Serializable — avtomatik seriyalaşdırma: nəyi və necə yazmağı Java özü həll edir.
  • Externalizable — əl ilə seriyalaşdırma: nəyi və necə saxlayıb/bərpa edəcəyinizi siz müəyyən edirsiniz.

2. Externalizable müqaviləsi: writeExternalreadExternal reallaşdırılır

Externalizable-dan istifadə etmək üçün:

  1. java.io.Externalizable interfeysini reallaşdırın.
  2. Mütləq iki metodu reallaşdırın:
    • void writeExternal(ObjectOutput out) throws IOException
    • void readExternal(ObjectInput in) throws IOException, ClassNotFoundException

Nümunə:

import java.io.*;

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

    // Mütləq public parametrsiz konstruktor!
    public User() {}

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeUTF(name);
        out.writeInt(age);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        name = in.readUTF();
        age = in.readInt();
    }

    @Override
    public String toString() {
        return name + " (" + age + ")";
    }
}

Vacibdir: hansı sahələrin və hansı ardıcıllıqla seriyalaşdırılacağına developer özü qərar verir. Lakin bir məcburi tələb var: sinifin public parametrsiz konstruktoru olmalıdır. Əgər o yoxdursa, deserializasiya zamanı proqram InvalidClassException atacaq.

3. Externalizable nə zaman istifadə olunmalıdır?

Externalizable-dan istifadə edin, əgər:

  • Məlumat formatına tam nəzarət lazımdır. Məsələn, yalnız bəzi sahələri seriyalaşdırmaq və ya onları xüsusi ardıcıllıqda/formatda yazmaq istəyirsiniz.
  • Performans və fayl ölçüsünün optimallaşdırılması. Standart seriyalaşdırma xidmət məlumatı (metaməlumat, sinif adları, tiplər və s.) əlavə edir. Externalizable ilə siz yalnız lazım olan məlumatları yazırsınız.
  • Geriyə uyğunluğun təmin edilməsi. Sinfin strukturu dəyişərsə, köhnə və yeni versiyaların məlumatlarını oxumaq üçün məntiqi əl ilə qura bilərsiniz.
  • Qeyri-standart obyektlərin seriyalaşdırılması. Məsələn, standart üsulla seriyalaşdırılması mümkün olmayan sahələriniz varsa (məsələn, transient, volatile və ya mürəkkəb strukturlar).

Nə zaman istifadə ETMƏMƏK lazımdır?

  • Əgər sizə tam nəzarət lazım deyilsə — Serializable-dan istifadə edin, bu daha sadə və təhlükəsizdir.
  • Sinif dəyişiklikləri zamanı məlumat formatının uyğunluğunu saxlaya biləcəyinizdən əmin deyilsinizsə.

4. Externalizable-ın Serializable ilə müqayisədə üstünlükləri və çatışmazlıqları

Üstünlüklər:

  • Seriyalaşdırmaya tam nəzarət. Nəyi və necə yazıb/oxuyacağınızı siz müəyyən edirsiniz.
  • Kompaktlıq. Artıq metaməlumat yoxdur — yalnız sizin məlumatlarınız.
  • Sürət. Məlumat azdırsa — yazma/oxuma daha sürətlidir.
  • Çeviklik. Müxtəlif format versiyalarını dəstəkləmək, sıxılma, şifrələmə və s. əlavə etmək olar.

Çatışmazlıqlar:

  • Əl ilə reallaşdırma — səhv etmək asandır. Yazma/oxuma ardıcıllığını səhv etsəniz, seriyalaşdırma «pozular» (xəta və ya yanlış məlumatlar olacaq).
  • Avtomatik dəstək yoxdur transient, serialVersionUID. Hər şeyi əvvəlcədən düşünmək və əl ilə reallaşdırmaq lazımdır.
  • Dəstəkləmək daha çətindir. Sinifin strukturu dəyişəndə seriyalaşdırma metodlarını yeniləməyi unutmaq olmaz.
  • Public parametrsiz konstruktor mütləqdir.
  • Daha az «sehr» — daha çox məsuliyyət.

5. Nümunələr: sadə obyektin seriyalaşdırılması və deserializasiyası

Obyektin seriyalaşdırılması

User user = new User("Alice", 30);

try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.bin"))) {
    out.writeObject(user);
}

Obyektin deserializasiyası

try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.bin"))) {
    User loaded = (User) in.readObject();
    System.out.println(loaded); // Alice (30)
}

Diqqət: əgər sahələrin yazılma/oxunma ardıcıllığını dəyişsəniz və ya hansısa sahəni seriyalaşdırmağı unutmusunuzsa, məlumatlar düzgün olmayacaq! writeExternalreadExternal metodları əməliyyatların ardıcıllığı baxımından ciddi şəkildə uzlaşdırılmalıdır.

Nümunə: sahələrin yalnız bir hissəsini seriyalaşdıraq

public class SecretUser implements Externalizable {
    private String login;
    private transient String password; // transient Externalizable üçün əhəmiyyət kəsb etmir

    public SecretUser() {}

    public SecretUser(String login, String password) {
        this.login = login;
        this.password = password;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeUTF(login);
        // Şifrəni seriyalaşdırmırıq!
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        login = in.readUTF();
        password = null; // şifrəni bərpa etmirik
    }
}

6. Təcrübə: seriyalaşdırılmış faylın ölçüsünü müqayisə etmək

Gəlin SerializableExternalizable vasitəsilə seriyalaşdırılan faylların «çəki»sini müqayisə edək.

Serializable ilə sinif

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

    public UserSerializable(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

Externalizable ilə sinif

public class UserExternalizable implements Externalizable {
    private String name;
    private int age;

    public UserExternalizable() {}

    public UserExternalizable(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeUTF(name);
        out.writeInt(age);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        name = in.readUTF();
        age = in.readInt();
    }
}

Müqayisə üçün kod

import java.io.*;

public class CompareSerialization {
    public static void main(String[] args) throws Exception {
        UserSerializable s = new UserSerializable("Bob", 25);
        UserExternalizable e = new UserExternalizable("Bob", 25);

        // Serializable
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("ser.bin"))) {
            out.writeObject(s);
        }

        // Externalizable
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("ext.bin"))) {
            out.writeObject(e);
        }

        System.out.println("Serializable file size: " + new File("ser.bin").length());
        System.out.println("Externalizable file size: " + new File("ext.bin").length());
    }
}

Nəticə:
ser.bin (Serializable) faylı adətən daha böyükdür — Java-nın xidmət məlumatını ehtiva edir. ext.bin (Externalizable) faylı isə yalnız sizin məlumatlarınızdır və adətən daha kiçik olur.

7. Externalizable ilə işləyərkən tipik səhvlər

Səhv №1: Public parametrsiz konstruktorun olmaması.
Externalizable reallaşdıran sinifin mütləq public arqumentsiz konstruktoru olmalıdır. O olmadıqda deserializasiya InvalidClassException atacaq.

Səhv №2: Sahələrin yazılma və oxunma ardıcıllığının pozulması.
writeExternalreadExternal metodları eyni ardıcıllıqda işləməlidir. Əgər yazarkən əvvəlcə name sahəsini saxlayıb, oxuyarkən əvvəl age sahəsini oxumağa cəhd etsəniz, məlumatlar təhrif olunacaq.

Səhv №3: Seriyalaşdırma zamanı sahələrin buraxılması.
Əgər writeExternal-da sahəni yazmağı unutmusunuzsa, deserializasiya zamanı o, null (istinad tipləri üçün) və ya 0 (rəqəm tipləri üçün) olacaq.

Səhv №4: transient və ya serialVersionUID-in səhv istifadəsi.
Serializable-dan fərqli olaraq, Externalizable üçün bu mexanizmlər avtomatik işləmir — hansı sahələrin saxlanılıb-saxlanılmayacağını siz özünüz idarə etməlisiniz.

Səhv №5: Sinif strukturunu dəyişdirib metodları yeniləməmək.
Sahələr əlavə edib/sildikdə və uyğun dəyişiklikləri writeExternalreadExternal-a tətbiq etmədikdə, köhnə saxlanılmış məlumatlar düzgün yüklənməyə bilər.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION