JavaRush /Java блог /Random UA /Як працює серіалізація в Java
ramhead
13 рівень

Як працює серіалізація в Java

Стаття з групи Random UA
У цій статті ми розповімо, що таке серіалізація і як вона працює у Java Як працює серіалізація в Java - 1

Вступ

Серіалізація об'єкта - це здатність об'єкта зберігати повну копію його та будь-яких інших об'єктів, на які він посилається, використовуючи потік виводу (наприклад, у зовнішній файл). Таким чином, об'єкт може бути відтворений із серіалізованої (збереженої) копії трохи пізніше, коли це буде потрібно. Серіалізація об'єктів, як нова можливість введена в JDK 1.1, надає функцію для перетворення груп або окремих об'єктів, потік бітів або масив байтів, для зберігання або передачі по мережі. І як було сказано, даний потік бітів або масив байтів можна перетворити назад в об'єкти Java. Головним чином це відбувається автоматично завдяки класам ObjectInputStreamта ObjectOutputStream. Програміст може вирішити реалізувати цю функцію шляхом реалізації інтерфейсуSerializableпід час створення класу. Процес серіалізації також відомий як маршалінг об'єкта, десеріалізація ж відома як демаршалінг . Серіалізація це механізм, що надає можливість об'єкту зберегти свою копію та всі інші об'єкти, на які посилається даний об'єкт, у зовнішній файл за допомогою класу ObjectOutputStream. Збережені можуть бути структури даних, діаграми, об'єкти класу JFrameабо будь-які інші об'єкти незалежно від їх типу. У той же час, серіалізація зберігає інформацію про те, якого типу об'єкта, щоб у подальшому, при десеріалізації, ця інформація використовувалася для відтворення точного типу об'єкта, яким він був. Отже, серіалізація надає такі можливості:
  • Система зберігання об'єктів, тобто: збереження їх властивостей у зовнішній файл, диск або базу даних.
  • Система дзвінків віддалених процедур.
  • Система розподілу об'єктів, наприклад, у програмних компонентах типу COM, COBRA.
  • Система ідентифікації змінних даних у часі.
Щоб повністю зрозуміти концепцію серіалізації, треба мати чітке розуміння двох інших концепцій — персистентності об'єктів і потоків. Тут ми трохи розповімо про кожну з них, щоби згадати. Повне пояснення щодо них, вимагало б окремому розділі кожної з цих концепцій.

Потоки:

Кожна програма повинна записувати свої дані до місця зберігання або каналу, і кожна програма повинна зчитувати дані з каналу або місця зберігання. У Java ці канали, куди програми записують і звідки програми зчитують дані, називаються Потоками ( Stream) . Як працює серіалізація в Java - 2
Малюнок 1. Графічне подання Потоків
Потоки в основному поділяються на два типи:
  • Байтові класи-потоки звані *Streams
  • Символьні класи-потоки звані *Reader та *Writer
Кожен потік запису даних містить набір методів запису. І кожен потік зчитування даних, відповідно, має подібний набір методів читання. Як тільки потік створюється, всі ці методи мають бути викликані.

Персистентність

Персистентність об'єкта - це здатність об'єкта жити або по-іншому - "пережити" виконання програми. Це означає, що будь-який об'єкт, створений у часі виконання, знищується "сміттярем" JVM, щоразу, коли цей об'єкт далі перестає використовуватися. Але у разі реалізації API персистентності, дані об'єкти не будуть знищуватись "сміттярем" JVM, замість чого їм буде дозволено "жити", що також дає можливість доступу до них при наступному запуску програми. Іншими словами, персистенція означає існування часу життя об'єкта, незалежно від часу життя програми, яка запущена. Один із способів реалізації персистентності це зберігання об'єктів де-небудь у зовнішньому файлі або в базі даних, а потім відновлення їх у пізніший час, використовуючи дані файли чи базу даних як джерела. Тут серіалізація і входить у гру. Будь-який неперсистентний об'єкт існує так довго, як довго працює JVM. Серіалізовані об'єкти — це просто об'єкти, перетворені на потоки, які потім зберігаються у зовнішній файл або передаються через мережу для зберігання та відновлення.

Реалізація інтерфейсу Serializable

Будь-який клас має реалізовувати інтерфейс java.io.Serializableдля серіалізації об'єктів цього класу. Інтерфейс Serializableне має методів і тільки маркерує клас, щоб можна було його ідентифікувати як серіалізований. Тільки поля об'єкта серіалізованого класу можна зберегти. Методи чи конструктори не зберігаються, як частини серіалізованого потоку. Якщо будь-який об'єкт діє як посилання інший об'єкт, то поля цього об'єкта також сериализованны, якщо клас цього об'єкта реалізує інтерфейс Serializable. Іншими словами, граф цього об'єкта, що отримується таким чином, серіалізуємо повністю. Граф об'єкта включає дерево чи структуру полів об'єкта та його подоб'єктов. Два головних класи, які допомагають реалізувати інтерфейс Seriliazable:
  • ObjectInputStream
  • ObjectOutputStream
Лістинг 1. Приклад простого класу, щоб показати серіалізацію
import java.io.*;
public class RandomClass implements Serializable {
 // Генерация рандомного значения
 private static int r() {
        return (int)(Math.random() * 10);
 }
    private int data[];
    // Конструктор
public RandomClass() {
        datafile = new int[r()];
        for (int i=0; i<datafile.length; i++)
        datafile[i]=r();
 }
    public void printout() {
 System.out.println("This RandomClass has "+datafile.length+" random integers");
 for (int i=0; i<datafile.length; i++) {
        System.out.print(datafile[i]+":");
        System.out.println();
    }
}
У наведеному вище коді створюється клас, який є серіалізується, т.к. "промаркований" інтерфейсом серіалізації. Клас створює масив випадкових цілих чисел, коли створюється його екземпляр. Наведений нижче код показує можливість запису об'єктів у потік, використовуючи клас ObjectOutputStream. Програма має масив цілих чисел, але для серіалізації ми не повинні перебирати її внутрішні об'єкти. Інтерфейс Seriliazableпіклується про це автоматично. Лістинг 2. Простий приклад серіалізації об'єктів для виведення файлу
import java.io.*;
import java.util.*;
public class OutSerialize {
    public static void main (String args[]) throws IOException {
        RandomClass rc1 = new RandomClass();
        RandomClass rc2 = new RandomClass();
//создание цепи потоков с потоком вывода об'єкта в конце
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("objects.dat"));
        Date now = new Date(System.currentTimeMillis());
//java.util.* был импортирован для использования класса Date
        out.writeObject(now);
        out.writeObject(rc1);
        out.writeObject(rc2);
out.close();
        System.out.println("I have written:");
System.out.println("A Date object: "+now);
        System.out.println("Two Group of randoms");
rc1.printout();
rc2.printout();
 }
}
Код нижче демонструє можливості класу ObjectInputStream, який зчитує серіалізовані дані із зовнішнього файлу до програми. Зауважте, що об'єкти зчитуються в тому самому порядку, в якому були записані у файл. Лістинг 3. Читання серіалізованих об'єктів або Десеріалізація
import java.io.*;
import java.util.*;
public class InSerialize {
 public static void main (String args[]) throws  IOException, ClassNotFoundException {
    ObjectInputStream in =  new ObjectInputStream (new FileInputStream("objects.dat"));
 Date d1 = (Date)in.readObject();
 RandomClass rc1 = (RandomClass)in.readObject();
    RandomClass rc2 = (RandomClass)in.readObject();
    System.out.println("I have read:");
    System.out.println("A Date object: "+d1);
    System.out.println("Two Group of randoms");
    rc1.printout();
rc2.printout();
 }
}
Майже всі класи Java можуть бути серіалізованими, включаючи класи AWT. Фрейм, який є вікном містить набір графічних компонентів. Якщо кадр серіалізований, механізм серіалізації піклується про це і серіалізує всі його компоненти та дані (позицію, зміст і т.д.). Деякі об'єкти класів Java не можуть бути серіалізовані, тому що містять дані, що посилаються на короткочасні ресурси операційних систем. Наприклад класи java.io.FileInputStreamта java.lang.Thread. Якщо об'єкт містить посилання на елементи, що не серіалізуються, вся операція серіалізації зазнає невдачі і буде викинуто виняток NotSerializableException. Якщо будь-який об'єкт посилається на посилання несеріалізованого об'єкта, його можна серіалізувати використовуючи ключове слово transient . Лістинг 4. Створення об'єктів, що серіалізуються, використовуючи ключове слово transient
public class Sclass implements Serializable{
public transient Thread newThread;
//помните, что поток(поток параллельного исполнения) по умолчанию не сериализуемый класс
    private String studentID;
    private int sum;
}

Безпека у Серіалізації

Серіалізація класу в Java передбачає передачу всіх його даних у зовнішній файл або базу даних через потік. Ми можемо обмежити дані, які будуть серіалізовані, коли того забажаємо. Є два способи зробити це:
  • Кожен параметр класу оголошений як transient , не серіалізуються (за замовчуванням усі параметри класу серіалізуються)
  • Або кожен параметр класу, який ми хочемо серіалізувати, позначається тегом Externalizable(за замовчуванням параметри не серіалізуються).
Поле даних не буде серіалізоване за допомогою ObjectOutputStream, коли воно буде викликане для об'єкта, якщо це поле даних даного об'єкта позначено як transient . Наприклад: private transient String password. З іншого боку, для явного оголошення даних об'єкта як серіалізується, ми повинні промаркувати клас як ExternalizablewriteExternalі readExteranlдля запису та читання даних цього об'єкта явно.

Висновок

Особливість серіалізації об'єктів використана у багатьох розподілених системах як спосіб передачі даних. Але серіалізація розкриває приховані деталі, таким чином руйнуючи справжність абстрактних типів даних, що руйнує інкапсуляцію. У той же час приємно знати, що дані серіалізованого об'єкта, ті самі дані, що були у вихідному, оригінальному об'єкті. Це також відмінна можливість реалізації інтерфейсу ObjectInputValidationі перевизначення методу validateObject(), навіть якщо використовуються кілька рядків коду. Якщо об'єкт не знайдено, ми можемо належним чином викинути виняток InvalidObjectException. Оригінал статті: How serialization works in Java
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ