Расширение стандартной сериализации
Некоторым сложно организованным классам требуется особый подход для сериализации. Для расширения стандартного механизма можно объявить в классе два метода с точно такой сигнатурой:
private void writeObject(
java.io.ObjectOutputStream out)
throws IOException;
private void readObject(
java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
Если в классе объявлены такие методы, то при сериализации объекта для записи его состояния будет вызван writeObject, который должен сгенерировать последовательность байт и записать ее в поток out, полученный в качестве аргумента. При этом можно вызвать стандартный механизм записи объекта путем вызова метода
out.defaultWriteObject();
Этот метод запишет все не- transient и не- static поля в поток данных.
В свою очередь, при десериализации метод readObject должен считать данные из потока in (также полученного в качестве аргумента) и восстановить значения полей класса. При реализации этого метода можно обратиться к стандартному механизму с помощью метода:
in.defaultReadObject();
Этот метод считывает описание объекта из потока и присваивает значения соответствующих полей в текущем объекте.
Если же процедура сериализации в корне отличается от стандартной, то для таких классов предназначен альтернативный интерфейс java.io.Externalizable.
При использовании этого интерфейса в поток автоматически записывается только идентификация класса. Сохранить и восстановить всю информацию о состоянии экземпляра должен сам класс. Для этого в нем должны быть объявлены методы writeExternal() и readExternal() интерфейса Externalizable. Эти методы должны обеспечить сохранение состояния, описываемого полями самого класса и его суперкласса.
При восстановлении Externalizable -объекта экземпляр создается путем вызова конструктора без аргументов, после чего вызывается метод readExternal.
Метод writeExternal имеет сигнатуру:
void writeExternal(ObjectOutput out)
throws IOException;
Для сохранения состояния вызываются методы ObjectOutput, с помощью которых можно записать как примитивные, так и объектные значения. Для корректной работы в соответствующем методе
void readExternal(ObjectInput in)
throws IOException,ClassNotFoundException;
эти значения должны быть считаны в том же самом порядке.
Классы Reader и Writer и их наследники
Рассмотренные классы – наследники InputStream и OutputStream – работают с байтовыми данными. Если с их помощью записывать или считывать текст, то сначала необходимо сопоставить каждому символу его числовой код. Такое соответствие называется кодировкой.
Известно, что Java использует кодировку Unicode, в которой символы представляются двухбайтовым кодом. Байтовые потоки зачастую работают с текстом упрощенно – они просто отбрасывают старший байт каждого символа. В реальных же приложениях могут использовать различные кодировки (даже для русского языка их существует несколько). Поэтому в версии Java 1.1 появился дополнительный набор классов, основывающийся на типах Reader и Writer. Их иерархия представлена на рис. 15.2.
Эта иерархия очень схожа с аналогичной для байтовых потоков InputStream и OutputStream. Главное отличие между ними – Reader и Writer работают с потоком символов ( char ). Только чтение массива символов в Reader описывается методом read(char[]), а запись в Writer – write(char[]).
В таблице 15.1 приведены соответствия классов для байтовых и символьных потоков.
Рис. 15.2. Иерархия классов Reader и Writer.
Таблица 15.1. Соответствие классов для байтовых и символьных потоков.
Байтовый поток |
Символьный поток |
---|---|
InputStream |
Reader |
OutputStream |
Writer |
ByteArrayInputStream |
CharArrayReader |
ByteArrayOutputStream |
CharArrayWriter |
Нет аналога |
InputStreamReader |
Нет аналога |
OutputStreamWriter |
FileInputStream |
FileReader |
FileOutputStream |
FileWriter |
FilterInputStream |
FilterReader |
FilterOutputStream |
FilterWriter |
BufferedInputStream |
BufferedReader |
BufferedOutputStream |
BufferedWriter |
PrintStream |
PrintWriter |
DataInputStream |
Нет аналога |
DataOutputStream |
Нет аналога |
ObjectInputStream |
Нет аналога |
ObjectOutputStream |
Нет аналога |
PipedInputStream |
PipedReader |
PipedOutputStream |
PipedWriter |
StringBufferInputStream |
StringReader |
Нет аналога |