Java. Серіалізація об’єктів. Ключове слово transient. Приклади




Серіалізація об’єктів. Ключове слово transient. Приклади


Зміст


Пошук на інших ресурсах:

1. Що таке серіалізація? Переваги серіалізації

Мова програмування Java має потужні засоби для забезпечення механізму серіалізації. Серіалізація – можливість об’єкту зберігати власні дані (стан об’єкту) в байтовому потоці з метою подальшого відтворення цих даних (стану) при наступних запусках програми. Іншими словами, поточні значення внутрішніх змінних в об’єкті можна зберегти (наприклад, у файл), а потім відновити в потрібний момент.

Механізм серіалізації дає наступні переваги:

  • об’єкт, для якого застосовується серіалізація, існує між запусками програми. Цей механізм називається легковаговим довгостроковим зберіганням об’єктів (lightweight persistence). Об’єкт спочатку зберігається на диску, потім відновлюється в початковий стан при наступному запуску програми;
  • забезпечується віддалений виклик методів Java, який дозволяє працювати з об’єктами, що “розміщуються” на віддалених комп’ютерах так, якби вони існували на вашому комп’ютері;
  • необхідність збереження поточної інформації про стан візуальних компонент JavaBean;
  • використання в об’єктах класів, що потребують збереження поточного стану.

 

2. Реалізація серіалізації у програмах на Java

У мові Java для того, щоб здійснити серіалізацію об’єкта в програмі потрібно дотримуватись певних рекомендацій. Усі класи, що зв’язані з серіалізацією, мають реалізувати інтерфейс Serializable. Це означає, що клас, який реалізує серіалізацію, повинен виглядати приблизно наступним чином:

class MySerializeClass implements Serializable {
    ...
}

так само клас, екземпляр якого серіалізується також має реалізувати інтерфейс Serializable:

class MyDataClass implements Serializable {
    ...
}

 

2.1. Запис об’єкту в файл

Якщо створено об’єкт dataObj деякого класу DataClass, то щоб зберегти цей об’єкт потрібно виконати наступні дії.

1. Створити вихідний потік fOut типу OutputStream. У випадку збереження об’єкту в файлі створюється вихідний потік типу FileOutputStream

FileOutputStream fOut = new FileOutputStream(filename);

тут filename – ім’я файлу, в який буде збережено об’єкт.

Клас FileOutputStream є підкласом абстрактного класу OutputStream.

2. Упакувати файловий об’єкт fOut в інший об’єкт типу ObjectOutputStream

ObjectOutputStream objOut = new ObjectOutputStream(fOut);

У результаті створюється потік objOut.

3. Записати екземпляр dataObj в потік objOut. Для цього використовується вбудований метод writeObject()

objOut.writeObject(dataObj);

4. Закрити обидва створені потоки

objOut.close();
fOut.close();

 

2.2. Читання об’єкту з файлу

Якщо об’єкт попередньо збережено, то для того, щоб відновити його стан з файлу, потрібно виконати наступні дії.

1. Створити екземпляр fInput класу FileInputStream

FileInputStream fInput = new FileInputStream(filename);

тут filename – ім’я файлу (тип String), в якому попередньо було збережено об’єкт.

2. Створити екземпляр objInput класу ObjectInputStream, в який упакувати екземпляр fInput класу FileInputStream

ObjectInputStream objInput = new ObjectInputStream(fInput);

3. Зчитати екземпляр з допомогою методу readObject(). Наприклад, якщо потрібно зчитати екземпляр класу DataClass, то код читання буде наступним

DataClass dObj = (DataClass)objInput.readObject();

4. Закрити потоки fInput та objInput

objInput.close();
fInput.close();

 

3. Яке призначення модифікатора transient?

Модифікатор transient використовується, коли виникає необхідність зберегти об’єкт (екземпляр) класу (виконати серіалізацію). Модифікатор transient встановлюється перед оголошенням внутрішньої змінної класу, значення якої не повинно зберігатись у випадку збереження об’єкту. З допомогою модифікатора transient можна програмно вказати дані, які не потрібно зберігати при серіалізацїі об’єкту.

Наприклад. У нижченаведеному класі Book змінна price оголошена з модифікатором transient.

class Book {
    String title;
    String author;
    int year;
    transient double price; // Ця змінна зберігатись не буде
}

Це означає, що при запису в файл будь-якого екземпляру класу Book, записуватись будуть значення змінних title, author, year крім змінної price.

 

4. Приклад серіалізації та використання модифікатора transient. Класи ObjectInputStream та ObjectOutputStream

У прикладі оголошується два класи:

  • клас DataClass, що містить дані, які будуть збережені. Зберігається екземпляр цього класу;
  • клас SerializeClass, який містить методи запису екземпляру типу DataClass.

Обидва класи реалізують інтерфейс Serializable.

У класі DataClass оголошуються:

  • внутрішні змінні a, b. Змінна b оголошена як transient-змінна. Це означає, що при запису в файл екземляру типу DataClass, значення змінної b записуватись не буде;
  • конструктор DataClass(int, int);
  • методи доступу до внутрішніх змінних GetA(), GetB(), SetA(), SetB();
  • метод Print(), що виводить значення внутрішніх змінних.

У класі SerializeClass оголошуються:

  • метод SaveData(), що реалізує запис екземпляру типу DataClass у заданий файл;
  • метод ReadData(), який повертає екземпляр типу DataClass, що був раніше записаний у файлі.

 

// Серіалізація об'єктів

import java.io.*;

// Клас, екземпляр якого потрібно буде записати/зчитати з файлу
class DataClass implements Serializable {
  // Внутрішня змінна
  private int a;
  private transient int b; // ця змінна зберігатись не буде

  // Конструктор
  DataClass(int a, int b) {
    this.a = a;
    this.b = b;
  }

  // Методи доступу
  int GetA() {
    return a;
  }

  int GetB() {
    return b;
  }

  void SetA(int a) {
    this.a = a;
  }

  void SetB(int b) {
    this.b = b;
  }

  // Метод, що виводить дані
  void Print() {
    System.out.println("a = " + a + ",   b = " + b);
  }
}

// Клас, що містить методи серіалізації (запису/читання даних) класу DataClass
public class SerializeClass implements Serializable {
  // Метод, що здійснює запис екземпляру класу DataClass у файл filename
  static void SaveData(DataClass dataObj, String filename)
      throws ClassNotFoundException, IOException {

    // 1. Створити екземпляр класу FileOutputStream - створити файловий потік
    FileOutputStream fOut = new FileOutputStream(filename);

    // 2. Створити екземпляр objOut класу ObjectOutputStream - потік запису об'єктів
    ObjectOutputStream objOut = new ObjectOutputStream(fOut);

    // 3. Записати екземпляр dataObj у потік objOut
    // 3.1. Записати коментар
    objOut.writeObject("Storage the dataObj instance\n");

    // 3.2. Записати екземпляр
    objOut.writeObject(dataObj);

    // 4. Закрити потік objOut
    objOut.close();

    // Закрити файловий потік
    fOut.close();
  }

  static DataClass ReadData(String filename)
      throws ClassNotFoundException, IOException      {

    // 1. Створити екземпляр класу FileInputStream
    FileInputStream fInput = new FileInputStream(filename);

    // 2. Створити екземпляр класу ObjectInputStream
    ObjectInputStream objInput = new ObjectInputStream(fInput);

    // 3. Зчитати дані з файлу filename в екземпляр dataObj
    // 3.1. Зчитати рядок пояснення
    String s = (String)objInput.readObject();

    // 3.2. Зчитати екземпляр типу DataClass
    DataClass dObj = (DataClass)objInput.readObject();

    // 4. Закрити потоки
    objInput.close();
    fInput.close();

    // 5. Повернути результат
    return dObj;
  }

  public static void main(String[] args) 
      throws ClassNotFoundException, IOException {

    // 1. Записати екземпляр класу DataClass у файл "myFile.dat"
    // 1.1. Створити об'єкт класу DataClass
    DataClass objData = new DataClass(5, 8);

    // 1.2. Записати об'єкт objData у файл "myFile.dat"
    SaveData(objData, "myFile.dat");

    // 2. Зчитати екземпляр класу DataClass з файлу "myFile.dat"
    // 2.1. Оголосити посилання на DataClass
    DataClass objData2;

    // 2.2. Зчитати дані в objData2
    objData2 = ReadData("myFile.dat");

    // 2.3. Вивести дані
    objData2.Print(); // a = 5,   b = 0 - значення змінної b не записувалось
  }
}

 

5. Чи зберігаються методи класу під час серіалізації?

Ні. При використанні механізму серіалізації, зберігаються тільки дані (внутрішні змінні).

 

6. Приклад класу, що містить методи серіалізації екземпляру даного класу

У прикладі розроблено клас Sphere, в якому визначені методи:

  • запису в файл поточного екземпляру класу;
  • читання даних з файлу поточного класу.

Клас містить методи серіалізації екземпляру даного класу.

Текст класу наступий

// Клас, що містить методи серіалізації об'єкту даного класу

import java.io.*;

class Sphere implements Serializable {

  // Внутрішня змінна - радіус сфери
  private double radius;

  // Методи доступу
  public double GetR() {
    return radius;
  }

  public void SetR(double radius) {
    this.radius = radius;
  }

  // Методи серіалізації об'єкту даного класу
  public void SaveToFile(String filename)
      throws ClassNotFoundException, IOException {

    // 1. Створити екземпляр класу FileOutputStream - створити файловий потік
    FileOutputStream fOut = new FileOutputStream(filename);

    // 2. Створити екземпляр objOut класу ObjectOutputStream - потік запису об'єктів
    ObjectOutputStream objOut = new ObjectOutputStream(fOut);

    // 3. Записати поточний екземпляр this у потік objOut
    objOut.writeObject(this);

    // 4. Закрити потік objOut
    objOut.close();

    // 5. Закрити файловий потік
    fOut.close();
  }

  public Sphere ReadFromFile(String filename)
      throws ClassNotFoundException, IOException {

    // 1. Створити екземпляр класу FileInputStream
    FileInputStream fInput = new FileInputStream(filename);

    // 2. Створити екземпляр класу ObjectInputStream
    ObjectInputStream objInput = new ObjectInputStream(fInput);

    // 3. Зчитати дані з файлу filename в екземпляр dObj
    Sphere dObj = (Sphere)objInput.readObject();

    // 4. Закрити потоки
    objInput.close();
    fInput.close();

    // 5. Повернути результат
    return dObj;
  }

  // Метод обчислення об'єму кулі
  public double Volume() {
    if (radius > 0)
      return 4.0 / 3.0 * Math.PI*radius*radius*radius;
    return 0.0;
  }
}

public class DemoSerialization implements Serializable {

  public static void main(String[] args)
      throws ClassNotFoundException, IOException {

    // 1. Записати екземпляр класу Sphere у файл "myfile.dat"
    // 1.1. Створити екземпляр sp
    Sphere sp = new Sphere();

    // 1.2. Встановити радіус
    sp.SetR(25.5);

    // 1.3. Записати sp у файл
    sp.SaveToFile("myfile.dat");

    // 2. Зчитати раніше записаний екземпляр з файлу
    // 2.1. Оголосити нове посилання sp2 типу Sphere
    Sphere sp2 = new Sphere();

    // 2.2. Зчитати sp2
    sp2 = sp2.ReadFromFile("myfile.dat");

    // 2.3. Вивести значення в sp2
    System.out.println("sp2.radius = " + sp2.GetR());
  }
}

Результат роботи програми

sp2.radius = 25.5

 


Зв’язані теми