Сериализация объектов. Ключевое слово 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. Это значит, что при записи в файл любого экземпляра класса Book, записываться будут значения переменных title, author, year кроме переменной price.
class Book { String title; String author; int year; transient double 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. Классы InputStreamReader, PrintStream. Создание потока ввода/вывода связанного с консолью. Перенаправление потоков ввода/вывода
- Работа с файлами в Java. Класс File. Основные методы работы
- Байтовые потоки. Классы DataInputStream, DataOutputStream, FileInputStream, FileOutputStream. Примеры использования
- Примеры реализации операций, которые модифицируют текстовые файлы. Классы FileReader, FileOutputStream, PrintStream
- Автоматическое закрытие файла. Оператор try с ресурсами. Примеры
⇑