Spec-Zone .ru
спецификации, руководства, описания, API
СОДЕРЖАНИЕ | ПРЕДЫДУЩИЙ | NEXT Спецификация Сериализации Объекта Java
версия 6.0

Архитектура системы





ГЛАВА 1


Темы:


1.1 Краткий обзор

Возможность сохранить и получить объекты JavaTM важна для создания всех кроме большинства переходных приложений. Ключ к хранению и получению объектов в сериализированной форме представляет состояние объектов, достаточных, чтобы восстановить объект (ы). Объекты, которые будут сохранены в потоке, могут поддерживать любого Serializable или Externalizable интерфейс. Для объектов JavaTM сериализированная форма должна быть в состоянии идентифицировать и проверить класс JavaTM, от которого содержание объекта было сохранено и восстановить содержание к новому экземпляру. Для сериализуемых объектов поток включает достаточную информацию, чтобы восстановить поля в потоке к совместимой версии класса. Для объектов Экстернэлизэйбла класс исключительно ответственен за внешний формат его содержания.

Объекты, которые будут сохранены и получены часто, обращаются к другим объектам. Те другие объекты должны храниться и получены одновременно, чтобы поддерживать отношения между объектами. Когда объект хранится, все объекты, которые достижимы от того объекта, хранятся также.

Цели для того, чтобы сериализировать объекты JavaTM к:


1.2 Запись в Объектный Поток

Запись объектов и примитивов к потоку является прямым процессом. Например:

// Serialize today's date to a file.
    FileOutputStream f = new FileOutputStream("tmp");
    ObjectOutput s = new ObjectOutputStream(f);
    s.writeObject("Today");
    s.writeObject(new Date());
    s.flush();
Сначала OutputStream, в этом случае a FileOutputStream, необходим, чтобы получить байты. Затем ObjectOutputStream создается что записи к FileOutputStream. Затем, строка "Сегодня" и объект Даты пишутся потоку. Более широко объекты пишутся с writeObject метод и примитивы пишутся потоку с методами DataOutput.

writeObject метод (см. Раздел 2.3, "writeObject Метод") сериализирует указанный объект и пересекает его ссылки на другие объекты в графе объектов рекурсивно, чтобы создать полное сериализированное представление графика. В потоке первая ссылка на любой объект приводит к объекту, сериализируемому или воплощенному и присвоение дескриптора для того объекта. Последующие ссылки на тот объект кодируются как дескриптор. Используя объектные дескрипторы сохраняет совместное использование и циклические ссылки, которые происходят естественно в графах объектов. Последующие ссылки на объектное использование только дескриптор, позволяющий очень компактное представление.

Специальная обработка требуется для массивов, перечислимых констант, и объектов типа Class, ObjectStreamClass, и String. Другие объекты должны реализовать любого Serializable или Externalizable интерфейс, который будет сохранен в или восстановлен от потока.

Примитивные типы данных пишутся потоку с методами в DataOutput интерфейс, такой как writeInt, writeFloat, или writeUTF. Отдельные байты и массивы байтов пишутся с методами OutputStream. За исключением сериализуемых полей, примитивные данные пишутся потоку в блочных записях данных с каждой записью, снабженной префиксом маркером и индикацией относительно числа байтов в записи.

ObjectOutputStream может быть расширен, чтобы настроить информацию о классах в потоке или заменить объекты, которые будут сериализированы. Обратитесь к annotateClass и replaceObject описания метода для деталей.


1.3 Чтение от Объектного Потока

Чтение объекта от потока, как запись, является прямым:

// Deserialize a string and date from a file.
    FileInputStream in = new FileInputStream("tmp");
    ObjectInputStream s = new ObjectInputStream(in);
    String today = (String)s.readObject();
    Date date = (Date)s.readObject();
Сначала InputStream, в этом случае a FileInputStream, необходим как исходный поток. Затем ObjectInputStream создается что чтения из InputStream. Затем, строка "Сегодня" и объект Даты читаются из потока. Обычно, объекты читаются с readObject метод и примитивы читаются из потока с методами DataInput.

readObject метод десериализовывает следующий объект в потоке и пересекает его ссылки на другие объекты рекурсивно, чтобы создать полный график сериализированных объектов.

Примитивные типы данных читаются из потока с методами в DataInput интерфейс, такой как readInt, readFloat, или readUTF. Отдельные байты и массивы байтов читаются с методами InputStream. За исключением сериализуемых полей, примитивные данные читаются из блочных записей данных.

ObjectInputStream может быть расширен, чтобы использовать настроенную информацию в потоке о классах или заменить объекты, которые были десериализованы. Обратитесь к resolveClass и resolveObject описания метода для деталей.


1.4 Объектные Потоки как Контейнеры

Объектная Сериализация производит и использует поток байтов, которые содержат один или более примитивов и объекты. Объекты, записанные потоку, поочередно, обращаются к другим объектам, которые также представляются в потоке. Объектная Сериализация производит только один потоковый формат, который кодирует и хранит содержавшие объекты.

Каждый объект, который действует как контейнер, реализует интерфейс, который позволяет примитивы и возражает, чтобы быть сохраненным в или полученным от него. Эти интерфейсы ObjectOutput и ObjectInput интерфейсы, который:

Каждый объект, который должен быть сохранен в потоке, должен явно позволить себе храниться и должен реализовать протоколы, должен был сохранить и восстановить его состояние. Объектная Сериализация определяет два таких протокола. Протоколы позволяют контейнеру спрашивать объект записать и считать его состояние.

Чтобы быть сохраненным в Объектном Потоке, каждый объект должен реализовать любого Serializable или Externalizable интерфейс:


1.5 Определение Сериализуемых Полей для Класса

Сериализуемые поля класса могут быть определены два различных пути. Сериализуемые поля по умолчанию класса определяются, чтобы быть непереходными и нестатическими полями. Это вычисление по умолчанию может быть переопределено, объявляя специальное поле в Serializable класс, serialPersistentFields. Это поле должно быть инициализировано с массивом ObjectStreamField объекты, которые перечисляют имена и типы сериализуемых полей. Модификаторы для поля обязаны быть частными, статичными, и заключительными. Если значение поля является нулем или является иначе не экземпляром ObjectStreamField[], или если у поля нет необходимых модификаторов, то поведение состоит в том, как будто поле не было объявлено вообще.

Например, следующее объявление копирует поведение по умолчанию.

class List implements Serializable {
    List next;

    private static final ObjectStreamField[] serialPersistentFields
                 = {new ObjectStreamField("next", List.class)};
}
При использовании serialPersistentFields чтобы определить поля Serializable для класса, больше нет ограничения, что сериализуемое поле должно быть полем в пределах текущего определения Serializable класс. writeObject и readObject методы Serializable класс может отобразить текущую реализацию класса сериализуемых полей класса, используя интерфейс, который описывается в Разделе 1.7, "Получая доступ к Сериализуемым Полям Класса." Поэтому, поля для a Serializable класс может измениться в более позднем выпуске, пока он поддерживает отображение назад на его поля Serializable, которые должны остаться совместимыми через границы выпуска.
Отметьте - есть, однако, ограничение к использованию этого механизма, чтобы определить сериализуемые поля для внутренних классов. Внутренние классы могут только содержать заключительные статические поля, которые инициализируются к константам или выражениям, созданным от констант. Следовательно, не возможно установить serialPersistentFields для внутреннего класса (хотя возможно установить это для статических задействованных классов). Для других ограничений, имеющих отношение к сериализации внутренних экземпляров класса, см. Раздел раздела  1.10, "Сериализуемый Интерфейс".

1.6 Документирование Сериализуемых Полей и Данных для Класса

Важно задокументировать сериализуемое состояние класса, чтобы включить функциональной совместимости с альтернативными реализациями Сериализуемого класса и к развитию класса документа. Документирование сериализуемого поля дает одному заключительную возможность рассмотреть, должно ли поле быть сериализуемым. Сериализация javadoc теги, @serial, @serialField, и @serialData, обеспечьте способ задокументировать сериализированную форму для Сериализуемого класса в пределах исходного кода. javadoc приложение распознает, что сериализация javadoc тегирует и генерирует спецификацию для каждого класса Serializable и Externalizable. См. Раздел C.1, "Реализация Альтернативы в качестве примера java.io. Файл" для примера, который использует эти теги.

Когда класс объявляется Сериализуемый, сериализуемое состояние объекта определяется сериализуемыми полями (по имени и тип) плюс дополнительные данные. Дополнительные данные могут только быть записаны явно writeObject метод a Serializable класс. Дополнительные данные могут быть считаны Serializable класс readObject метод или сериализация пропустят непрочитанные дополнительные данные.

Когда класс объявляется Экстернэлизэйблом, данные, которые пишутся потоку самим классом, определяют сериализированное состояние. Класс должен определить порядок, типы, и значение каждой данной величины, которая пишется потоку. Класс должен обработать свое собственное развитие, так, чтобы он мог продолжать читать данные, записанные и данные записи, которые могут быть считаны предыдущими версиями. Класс должен скоординировать с суперклассом, сохраняя и восстанавливая данные. Расположение данных суперклассов в потоке должно быть определено.

Разработчик Сериализуемого класса должен гарантировать, что информация, сохраненная для класса, является подходящей для персистентности и следует за определенными сериализацией правилами для функциональной совместимости и развития. Развитие класса объясняется более подробно в  Главе 5, "Управление версиями Сериализуемых Объектов."


1.7 Доступ к Сериализуемым Полям Класса

Сериализация обеспечивает два механизма для того, чтобы они получили доступ к сериализуемым полям в потоке: Механизм по умолчанию используется автоматически, читая или при записи объектов, которые реализуют Serializable соедините интерфейсом и не сделайте никакой дальнейшей настройки. Сериализуемые поля отображаются на соответствующие поля класса, и значения или пишутся потоку от тех полей или читаются в и присваиваются соответственно. Если класс обеспечивает writeObject и readObject методы, механизм по умолчанию может быть вызван, вызывая defaultWriteObject и defaultReadObject. Когда writeObject и readObject методы реализуются, у класса есть возможность изменить сериализуемые значения полей прежде, чем они будут записаны или после того, как они читаются.

Когда механизм по умолчанию не может использоваться, сериализуемый класс может использовать putFields метод ObjectOutputStream помещать значения для сериализуемых полей в поток. writeFields метод ObjectOutputStream помещает значения в правильном порядке, затем пишет им в поток, используя существующий протокол для сериализации. Соответственно, readFields метод ObjectInputStream читает значения из потока и делает их доступными для класса по имени в любом порядке. См. Раздел 2.2, "ObjectOutputStream. Класс PutField" и Раздел 3.2, "ObjectInputStream. Класс GetField." для подробного описания Сериализуемого Полевого API.


1.8 Интерфейс ObjectOutput

ObjectOutput интерфейс обеспечивает абстрактный, основанный на потоке интерфейс, чтобы возразить хранению. Это расширяет интерфейс DataOutput, таким образом, те методы могут использоваться для того, чтобы записать примитивные типы данных. Объекты, которые реализуют этот интерфейс, могут использоваться, чтобы сохранить примитивы и объекты.

package java.io;

public interface ObjectOutput extends DataOutput
{
    public void writeObject(Object obj) throws IOException;
    public void write(int b) throws IOException;
    public void write(byte b[]) throws IOException;
     public void write(byte b[], int off, int len) throws IOException;
    public void flush() throws IOException;
    public void close() throws IOException;
}
The writeObject метод используется, чтобы записать объект. Брошенные ошибки отражения исключений, получая доступ к объекту или его полям, или исключениям, которые происходят в письменной форме с хранением. Если какое-либо исключение выдается, базовое хранение может быть повреждено. Если это происходит, обратитесь к объекту, который реализует этот интерфейс для получения дополнительной информации.

1.9 Интерфейс ObjectInput

ObjectInput интерфейс обеспечивает абстрактный поток базируемый интерфейс, чтобы возразить извлечению. Это расширяется DataInput взаимодействуйте через интерфейс, таким образом, те методы для того, чтобы считать примитивные типы данных доступны в этом интерфейсе.

package java.io;

public interface ObjectInput extends DataInput
{
    public Object readObject()
        throws ClassNotFoundException, IOException;
    public int read() throws IOException;
    public int read(byte b[]) throws IOException;
    public int read(byte b[], int off, int len) throws IOException;
    public long skip(long n) throws IOException;
    public int available() throws IOException;
    public void close() throws IOException;
}
readObject метод используется, чтобы считать и возвратить объект. Брошенные ошибки отражения исключений, получая доступ к объектам или его полям или исключениям, которые происходят в чтении от хранения. Если какое-либо исключение выдается, базовое хранение может быть повреждено. Если это происходит, обратитесь к объекту, реализовывая этот интерфейс для дополнительной информации.

1.10 Сериализуемый Интерфейс

Объектная Сериализация производит поток с информацией о классах JavaTM для объектов, которые сохраняются. Для сериализуемых объектов достаточная информация сводится к восстановлению к тем объектам, даже если различное (но совместимый) версия реализации класса присутствует. Serializable интерфейс определяется, чтобы идентифицировать классы, которые реализуют сериализуемый протокол:

package java.io;

public interface Serializable {};
Сериализуемый класс должен сделать следующее:
(Используйте serialPersistentFields элемент, чтобы явно объявить их сериализуемый или использовать переходное ключевое слово, чтобы обозначить несериализуемые поля.)
Класс может дополнительно определить следующие методы:
(См. Раздел 2.5, "writeReplace Метод" для дополнительной информации.)
(См. Раздел 3.7, "readResolve Метод" для дополнительной информации.)
ObjectOutputStream и ObjectInputStream позвольте сериализуемые классы, на которых они работают, чтобы развиться (позвольте изменения классам, которые являются совместимыми с более ранними версиями классов). См. Раздел 5.5, "Совместимое Развитие Типа JavaTM" для информации о механизме, который используется, чтобы позволить совместимые изменения.
Отметьте - Сериализация внутренних классов (то есть, вложенные классы, которые не являются статическими задействованными классами), включая локальные и анонимные классы, строго обескураживается по нескольким причинам. Поскольку внутренние классы, объявленные в нестатических контекстах, содержат неявные непереходные ссылки на включение экземпляров класса, сериализируя такой внутренний экземпляр класса приведет к сериализации его связанного внешнего экземпляра класса также. Синтетические поля, сгенерированные javac (или другие компиляторы JavaTM), чтобы реализовать внутренние классы являются зависящими от реализации и может измениться между компиляторами; различия в таких полях могут разрушить совместимость так же как привести к конфликтному значению по умолчанию serialVersionUID значения. Имена, присвоенные локальным и анонимным внутренним классам, являются также зависящими от реализации и могут отличаться между компиляторами. Так как внутренние классы не могут объявить статические элементы кроме времени компиляции постоянные поля, они не могут использовать serialPersistentFields механизм, чтобы определять сериализуемые поля. Наконец, потому что у внутренних классов, связанных с внешними экземплярами, нет конструкторов нулевого параметра (конструкторы таких внутренних классов неявно принимают экземпляр включения как предварительно ожидаемый параметр), они не могут реализовать Externalizable. Ни одна из упомянутых выше проблем, однако, не применяется к статическим задействованным классам.

1.11 Интерфейс Externalizable

Для объектов Экстернэлизэйбла только идентификационные данные класса объекта сохраняются контейнером; класс должен сохранить и восстановить содержание. Externalizable интерфейс определяется следующим образом:

package java.io;

public interface Externalizable extends Serializable
{
    public void writeExternal(ObjectOutput out)
        throws IOException;

    public void readExternal(ObjectInput in)
        throws IOException, java.lang.ClassNotFoundException;
}
Класс объекта Externalizable должен сделать следующее:
(Это должно явно скоординировать с его супертипом, чтобы сохранить его состояние.)
(Это должно явно скоординировать с супертипом, чтобы сохранить его состояние.)

Отметьте - writeExternal и readExternal методы общедоступны и повышают риск, что клиент может быть в состоянии записать или считать информацию в объекте кроме при использовании его методов и полей. Эти методы должны использоваться только, когда информация, сохраненная объектом, не чувствительна или когда представление этого не представляет угрозу безопасности.

Отметьте - у Внутренних классов, связанных с включением экземпляров, не может быть конструкторов без аргументов, так как конструкторы таких классов неявно принимают экземпляр включения как предварительно ожидаемый параметр. Следовательно Externalizable интерфейсный механизм не может использоваться для внутренних классов, и они должны реализовать Serializable интерфейс, если они должны быть сериализированы. Несколько ограничений существуют для сериализуемых внутренних классов также, однако; см. Раздел 1.10, "Сериализуемый Интерфейс", для полного перечисления.
Класс Externalizable может дополнительно определить следующие методы:
(См. Раздел 2.5, "writeReplace Метод" для дополнительной информации.)
(См. Раздел 3.7, "readResolve Метод" для дополнительной информации.)

1.12 Сериализации Перечислимых Констант

Перечислимые константы сериализируются по-другому чем обычный сериализуемый или объекты externalizable. Сериализированная форма перечислимой константы состоит исключительно из ее имени; значения полей константы не присутствуют в форме. Сериализировать перечислимую константу, ObjectOutputStream пишет значение, возвращенное перечислимой константой name метод. Десериализовывать перечислимую константу, ObjectInputStream читает постоянное имя из потока; десериализованная константа тогда получается, вызывая java.lang.Enum.valueOf метод, передавая перечислимый тип константы наряду с полученным постоянным именем как параметры. Как другое сериализуемое или объекты externalizable, перечислимые константы могут функционировать как цели обратных ссылок, появляющихся впоследствии в потоке сериализации.

Процесс, которым сериализируются перечислимые константы, не может быть настроен: любой специфичный для класса writeObject, readObject, readObjectNoData, writeReplace, и readResolve методы, определенные перечислимыми типами, игнорируются во время сериализации и десериализации. Точно так же любой serialPersistentFields или serialVersionUID полевые объявления также игнорируются - у всех перечислимых типов есть фиксированный serialVersionUID из 0L. Документирование сериализуемых полей и данных для перечислимых типов является ненужным, так как нет никакого изменения в типе отправленных данных.


1.13 Уязвимой информации Защиты

Разрабатывая класс, который обеспечивает управляемый доступ к ресурсам, забота должна быть проявлена, чтобы защитить уязвимую информацию и функции. Во время десериализации восстанавливается частное состояние объекта. Например, дескриптор файла содержит дескриптор, который обеспечивает доступ к ресурсу операционной системы. Возможность подделать дескриптор файла позволила бы некоторые формы несанкционированного доступа, начиная с восстановления состояния делается от потока. Поэтому, время выполнения сериализации должно проявить консервативный подход и не доверять потоку, чтобы содержать только допустимые представления объектов. Чтобы избежать ставить под угрозу класс, чувствительное состояние объекта не должно быть восстановлено от потока, или это должно быть повторно проверено классом. Несколько методов доступны, чтобы защитить уязвимые данные в классах.

Самый легкий метод должен отметить поля, которые содержат уязвимые данные как частный переходный процесс. Переходные поля не являются персистентными и не будут сохранены никаким механизмом персистентности. Отмечание поля будет препятствовать тому, чтобы состояние появилось в потоке и от того, чтобы быть восстановленным во время десериализации. Начиная с записи и чтения (частных полей) не может быть заменен за пределами класса, переходные поля класса безопасны.

Особенно чувствительные классы не должны быть сериализированы вообще. Чтобы выполнить это, объект не должен реализовать ни одного Serializable или Externalizable интерфейс.

Некоторые классы могут счесть выгодным, чтобы позволить писать и читать, но определенно обработать и подтвердить состояние, поскольку это десериализовывается. Класс должен реализовать writeObject и readObject методы, чтобы сохранить и восстановить только соответствующее состояние. Если доступ должен быть лишен, бросая a NotSerializableException предотвратит дальнейший доступ.



СОДЕРЖАНИЕ | ПРЕДЫДУЩИЙ | NEXT
Авторское право © 2005, 2010, Oracle и/или его филиалы. Все права защищены.