Вторник, 19.03.2024, 10:07
Приветствую Вас, Гость |
Меню сайта
Наш опрос
Нужен ли форум на этом сайте?
Всего ответов: 1296
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Сериализация Java
Сериализация Java связана еще с одной важной библиотекой платформы Java. Сериализация в основном используется для персистенции объектов и взаимодействия с удаленными объектами - это два случая, когда нужно иметь возможность создать копию состояния объекта, чтобы позднее восстановить его. В этом разделе содержится краткая информация об API Java Serialization и показано, как использовать его в своих программах.
Что такое сериализация объектов?
Сериализация - это процесс, когда состояние объекта и его метаданные (например, имя класса объекта и имена его атрибутов) сохраняются в особом двоичном формате. Преобразование объекта в этот формат - сериализация - позволяет сохранить всю информацию, необходимую для восстановления (или десериализации) объекта в нужное время.
Существует два основных способа сериализации объекта:
Персистенция объекта - это хранение состояния объекта в постоянном механизме персистенции, таком как база данных.
Дистанцирование (remoting) объекта означает передачу объекта в другой компьютер или систему.
В начало
java.io.Serializable
Первым шагом к выполнению работы по сериализации является предоставление объектам возможности использовать этот механизм. Каждый объект, который нужно сериализовать, должен реализовать интерфейс java.io.Serializable:
import java.io.Serializable;
public class Person implements Serializable {
// и т.д.
}

Интерфейс Serializable помечает объекты класса Person для среды исполнения как сериализуемые. Каждый подкласс Person также помечается как сериализуемый.
При попытке сериализовать объект любые несериализуемые атрибуты объекта вызовут выдачу средой исполнения Java исключения NotSerializableException. Этим можно управлять с помощью ключевого слова transient, которое указывает среде времени выполнения, что пытаться сериализовать те или иные атрибуты не нужно. В этом случае сам программист несет ответственность за восстановление этих атрибутов для правильного функционирования объекта.
Сериализация объекта
Теперь рассмотрим пример, в котором сочетается все, что вы только что узнали об операциях ввода/вывода Java и о сериализации.
Предположим, что мы создали и заполнили объект Manager (напомним, что Manager находится в графе наследования Person, который является сериализуемым объектом), а теперь хотим сериализовать этот объект в выходной поток OutputStream, в данном случае, в файл. Этот процесс показан в листинге 29.

Листинг 29. Сериализация объекта
Manager m = new Manager();
m.setEmployeeNumber("0001");

m.setGender(Gender.FEMALE);
m.setAge(29);
m.setHeight(170);
m.setName("Mary D. Boss");
m.setTaxpayerIdentificationNumber("123-45-6789");
log.info("About to write object using serialization... object looks like:");
m.printAudit(log);
try {
String filename = "Manager-" + m.hashCode() + ".ser";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename));
oos.writeObject(m);
log.info("Wrote object...");
} catch (Exception e) {
log.log(Level.SEVERE, "Caught Exception processing object", e);
}

Первым шагом является создание объекта и установка некоторых значений атрибутов. Далее, создаем выходной поток OutputStream, в данном случае это FileOutputStream, а затем вызываем writeObject() для этого потока. writeObject () - это метод, который использует Java-сериализацию для преобразования объекта в поток.
В этом примере объект сохраняется в файле, но для любой сериализации используется одна и та же технология.
Десериализация объекта
Весь смысл сериализации объекта заключается в том, чтобы иметь возможность впоследствии восстановить, или десериализовать его. Листинг 30 считывает только что сериализованный файл и десериализует его содержание, тем самым восстанавливая состояние объекта Manager.

Листинг 30. Десериализация объекта

Manager m = new Manager();
m.setEmployeeNumber("0001");
m.setGender(Gender.FEMALE);
m.setAge(29);
m.setHeight(170);
m.setName("Mary D. Boss");
m.setTaxpayerIdentificationNumber("123-45-6789");
log.info("About to write object using serialization... object looks like:");
m.printAudit(log);
try {
String filename = "Manager-" + m.hashCode() + ".ser";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename));
oos.writeObject(m);
log.info("Wrote object...");

ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
m = (Manager)ois.readObject();
log.info("Read object using serialization... object looks like:");
m.printAudit(log);
} catch (Exception e) {
log.log(Level.SEVERE, "Caught Exception processing object", e);
}

В большинстве случаев маркировка объектов как сериализуемых - это все, о чем вам когда-нибудь придется беспокоиться в связи с сериализацией. В тех случаях, когда нужно явно выполнять сериализацию и десериализацию объектов, можно использовать подход, показанный в листингах 29 и 30. Но по мере развития объектов вашего приложения и добавления/удаления их атрибутов сериализация приобретает новый уровень сложности.
В начало
Свойство serialVersionUID
В ранние дни промежуточного ПО и удаленной связи объектов разработчики в значительной мере сами отвечали за управление "форматом передачи" своих объектов, что вызывало бесконечные проблемы по мере развития технологии.
Предположим, что вы добавили атрибут к объекту, скомпилировали его и распространили код на все машины кластера приложения. Объект хранится на компьютере с одной версией кода сериализации, но доступен для других машин, которые могут иметь разные версии кода. Когда эти машины пытались десериализовать объект, часто происходили неприятные вещи.
Метаданные Java-сериализации – информация, включенная в двоичный формат сериализации, – имеют сложную структуру и решают многие проблемы, досаждающие ранним разработчикам промежуточного ПО. Но всех проблем они тоже не решают.
При Java-сериализации используется свойство serialVersionUID, которое помогает справиться с разными версиями объектов в сценарии сериализации. Вам не нужно декларировать это свойство для своих объектов; по умолчанию платформы Java использует алгоритм, который вычисляет его значение на основе атрибутов класса, его имени и положения в локальном кластере. В большинстве случаев это работает отлично. Но при добавлении или удалении атрибутов это динамически сгенерированное значение изменится, и среда исполнения Java выдаст исключение InvalidClassException.
Чтобы избежать этого, нужно взять в привычку явное объявление serialVersionUID:
import java.io.Serializable;
public class Person implements Serializable {
private static final long serialVersionUID = 20100515;
// и т.д.
}

Я рекомендую использовать некую схему для номера версии serialVersionUID (в примере я использую текущую дату), причем нужно объявить его как private static final с типом long.
Вы можете спросить, когда изменять это свойство? Краткий ответ заключается в том, что его нужно изменять его всякий раз при внесении несовместимых изменений в класс, что обычно означает, что вы удалили атрибут. Если на компьютере имеется версия объекта, в которой атрибут удален, и этот объект переносится на машину с версией объекта, в которой этот атрибут ожидается, могут произойти неприятности.
В качестве золотого правила, при каждом добавлении или удалении элементов класса (то есть атрибутов и методов) нужно изменять его serialVersionUID. Лучше получить исключение InvalidClassException на другом конце "провода", чем приложение с ошибкой из-за несовместимых изменений класса.
Форма входа
Поиск
Мы в сети
Реклама
Для того чтобы не видеть рекламу в правом верхнем углу сайта пройдите простую процедуру регистрации
ФОРУМ
У нас наконецто появился форум! Добро пожаловать! Будьте первыми, задайте направление форуму! =)
--- Не стесняемся - заходим на форум! ---