System.out.println('readInt: ' + inData.readInt()); System.out.println('readLong: ' + inData.readLong()); System.out.println('readDouble: ' + inData.readDouble()); inData.close(); System.out.println('Чтение в измененной последовательности:'); in = new ByteArrayInputStream(bytes); inData = new DataInputStream(in); System.out.println('readInt: ' + inData.readInt()); System.out.println('readDouble: ' + inData.readDouble()); System.out.println('readLong: ' + inData.readLong()); inData.close(); } catch (Exception e) { System.out.println('Impossible IOException occurs: ' + e.toString()); e.printStackTrace(); } Пример 15.9.
Результат выполнения программы:
Чтение в правильной последовательности:
readByte: -128 readInt: 128 readLong: 128 readDouble: 128.0
Чтение в измененной последовательности:
readInt: -2147483648 readDouble: -0.0 readLong: -9205252085229027328
Итак, значение любого примитивного типа может быть передано и считано из потока данных.
Сериализация объектов (serialization)
Для объектов процесс преобразования в последовательность байт и обратно организован несколько сложнее – объекты имеют различную структуру, хранят ссылки на другие объекты и т.д. Поэтому такая процедура получила специальное название - сериализация (serialization), обратное действие, – то есть воссоздание объекта из последовательности байт – десериализация.
Поскольку сериализованный объект – это последовательность байт, которую можно легко сохранить в файл, передать по сети и т.д., то и объект затем можно восстановить на любой машине, вне зависимости от того, где проводилась сериализация. Разумеется, Java позволяет не задумываться при этом о таких факторах, как, например, используемая операционная система на машине-отправителе и получателе. Такая гибкость обусловила широкое применение сериализации при создании распределенных приложений, в том числе и корпоративных (enterprise) систем.
Стандартная сериализация
Для представления объектов в виде последовательности байт определены унаследованные от DataInput и DataOutput интерфейсы ObjectInput и ObjectOutput, соответственно. В java.io имеются реализации этих интерфейсов – классы ObjectInputStream и ObjectOutputStream.
Эти классы используют стандартный механизм сериализации, который предлагает JVM. Для того, чтобы объект мог быть сериализован, класс, от которого он порожден, должен реализовывать интерфейс java.io.Serializable. В этом интерфейсе не определен ни один метод. Он нужен лишь для указания, что объекты класса могут участвовать в сериализации. При попытке сериализовать объект, не имеющий такого интерфейса, будет брошен java.io.NotSerializableException.
Чтобы начать сериализацию объекта, нужен выходной поток OutputStream, в который и будет записываться сгенерированная последовательность байт. Этот поток передается в конструктор ObjectOutputStream. Затем вызовом метода writeObject() объект сериализуется и записывается в выходной поток. Например:
ByteArrayOutputStream os = new ByteArrayOutputStream(); Object objSave = new Integer(1); ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(objSave);
Чтобы увидеть, во что превратился объект objSave, можно просмотреть содержимое массива:
byte[] bArray = os.toByteArray();
А чтобы восстановить объект, его нужно десериализовать из этого массива:
ByteArrayInputStream is = new ByteArrayInputStream(bArray); ObjectInputStream ois = new ObjectInputStream(is); Object objRead = ois.readObject();
Теперь можно убедиться, что восстановленный объект идентичен исходному:
System.out.println('readed object is: ' + objRead.toString()); System.out.println('Object equality is: ' + (objSave.equals(objRead))); System.out.println('Reference equality is: ' + (objSave==objRead));