Несколько основных моментов насчет сериализации.
Простейший пример сериализации и десериализации объекта класса в файл:
Простейший пример сериализации и десериализации объекта класса в файл:
import java.io.Serializable; class TestSerial implements Serializable { private static final long serialVersionUID = 565645645688l; private byte field1 = 100; private String field2 = "field2"; public byte getField1() { return field1; } public String getField2() { return field2; } //Реализация алгоритма сериализации public static void serialize() throws IOException { FileOutputStream fos = new FileOutputStream("temp.out"); ObjectOutputStream oos = new ObjectOutputStream(fos); TestSerial ts = new TestSerial(); oos.writeObject(ts); oos.flush(); oos.close(); } //Код, приведённый в методе serialize сериализует состояние экземпляра класса TestSerial //в файл temp.out. Для воссоздания объекта, нужно произвести //десериализацию, как показано в методе deserialize. //Воссоздание сериализованного объекта public static void deserialize() throws IOException { FileInputStream fis = new FileInputStream("temp.out"); ObjectInputStream oin = new ObjectInputStream(fis); TestSerial ts = (TestSerial) oin.readObject(); System.out.println("field1="+ts.getField1()); System.out.println("field2="+ts.getField2()); } }
Модификаторы полей
Существует такой модификатор поля как transient. Он означает, что это поле не должно быть сериализовано. При десериализации объекта класса такому полю присваивается значение null.
При сериализации поля, имеющие модификатор static, не сериализуются. Соответственно, после десериализации это поле значения не меняет.
Поля с модификатором final сериализуются как и обычные.
SerialVersionUID
Еще один очень важный момент. При стандартной сериализации учитывается порядок объявления полей в классе. Потому, при изменении порядка десериализация пройдет не так как положено. Чтобы этого избежать, добавлен следующий механизм. В каждый класс, реализующий интерфейс Serializable, на стадии компиляции добавляется еще одно поле – private static final long serialVersionUID. Это поле содержит уникальный идентификатор версии сериализованного класса. Оно вычисляется по содержимому класса – полям, их порядку объявления, методам, их порядку объявления. Соответственно, при любом изменении в классе это поле поменяет свое значение, и при загрузке, если значение поля изменилось в текущем классе - будет выдана ошибка.
Есть, однако, способ эту проверку если обойти. Это может оказаться полезным, если набор полей класса и их порядок уже определен, а методы класса могут меняться. В этом случае сериализации ничего не угрожает, однако стандартный механизм не даст десериализовать данные с использованием байткода измененого класса. Но, как я уже сказал, его можно обмануть. А именно – вручную в классе определить поле private static final long serialVersionUID. Значение его для этого класса можно получить, использовав утилиту serialver, входящую в поставку SDK. После такого определения значение поля будет фиксировано, следовательно, десериализация всегда будет разрешена.
Более того, в версии 5.0 в документации появилось приблизительно следующее: крайне рекомендуется всем сериализуемым классам декларировать это поле в явном виде, ибо вычисление по умолчанию очень чувствительно к деталям структуры класса, которые могут различаться в зависимости от реализации компилятора, и вызывать таким образом неожиданные InvalidClassException при десериализации. Объявлять это поле лучше как private, т.к. оно относится исключительно к классу, в котором объявляется. Хотя в спецификации модификатор не оговорен.
Кроме сериализации путем имплементирования класса Serializable, существует ещё один более "продвинутый" способ сериализации - путем имплелементирования класса Externalizable.
Комментариев нет:
Отправить комментарий