Серіалізація об’єктів. Ключове слово transient. Приклади
Зміст
- 1. Що таке серіалізація? Переваги серіалізації
- 2. Реалізація серіалізації у програмах на Java
- 3. Яке призначення модифікатора transient?
- 4. Приклад серіалізації та використання модифікатора transient. Класи ObjectInputStream та ObjectOutputStream
- 5. Чи зберігаються методи класу під час серіалізації?
- 6. Приклад класу, що містить методи серіалізації екземпляру даного класу
- Зв’язані теми
Пошук на інших ресурсах:
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
⇑
Зв’язані теми
- Система вводу/виводу Java. Потік. Байтові потоки. Символьні потоки. Стандартні потоки
- Робота з консоллю в Java. Класи InputStreamReader, PrintStream. Створення потоку вводу/виводу зв’язаного з консоллю. Перенаправлення потоків вводу виводу
- Робота з файлами в Java. Клас File. Основні методи роботи
- Байтові потоки. Класи DataInputStream, DataOutputStream, FileInputStream, FileOutputStream. Приклади використання
- Приклади реалізації операцій, які модифікують текстові файли. Класи FileReader, FileOutputStream, PrintStream
⇑