Перейти к содержимому

Что делает метод reset в классе objectoutputstream

  • автор:

Object Output Stream. Reset Метод

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

Сброс не учитывает состояние всех объектов, уже записанных в поток.

[Android.Runtime.Register("reset", "()V", "GetResetHandler")] public virtual void Reset ();
[] abstract member Reset : unit -> unit override this.Reset : unit -> unit
Исключения

Значение , если reset() вызывается во время сериализации объекта .

Комментарии

Сброс не учитывает состояние всех объектов, уже записанных в поток. Состояние сброса совпадает с состоянием объекта ObjectOutputStream. Текущая точка в потоке помечается как сбросная, поэтому соответствующий объект ObjectInputStream будет сброшен в той же точке. Объекты, ранее записанные в поток, не будут называться уже имеющимися в потоке. Они будут снова записаны в поток.

Части этой страницы являются изменениями, основанными на работе, созданной и совместно используемой проектом Android и используемой в соответствии с условиями, Creative Commons 2.5 Attribution License.

Object Output Stream Класс

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

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

[Android.Runtime.Register("java/io/ObjectOutputStream", DoNotGenerateAcw=true)] public class ObjectOutputStream : Java.IO.OutputStream, IDisposable, Java.Interop.IJavaPeerable, Java.IO.IObjectOutput
[] type ObjectOutputStream = class inherit OutputStream interface IObjectOutput interface IDataOutput interface IJavaObject interface IDisposable interface IJavaPeerable

Наследование
ObjectOutputStream
Реализации

Комментарии

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream. Объекты можно считывать (воссоздать) с помощью ObjectInputStream. Постоянное хранение объектов можно выполнить с помощью файла для потока. Если поток является потоком сетевых сокетов, объекты можно восстановить на другом узле или в другом процессе.

В потоки можно записывать только объекты, поддерживающие интерфейс java.io.Serializable. Класс каждого сериализуемого объекта кодируется, включая имя класса и сигнатуру класса, значения полей и массивов объекта, а также закрытие всех других объектов, на которые ссылается исходный объект.

Метод writeObject используется для записи объекта в поток. Любой объект, включая strings и массивы, записывается с помощью writeObject. В поток можно записать несколько объектов или примитивов. Объекты должны считываться обратно из соответствующего objectInputstream с теми же типами и в том же порядке, что и они были записаны.

Примитивные типы данных также можно записать в поток с помощью соответствующих методов из DataOutput. Строки также можно записать с помощью метода writeUTF.

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

Например, чтобы написать объект, который может быть прочитан в примере в ObjectInputStream:

FileOutputStream fos = new FileOutputStream("t.tmp"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeInt(12345); oos.writeObject("Today"); oos.writeObject(new Date()); oos.close(); 

Классы, требующие специальной обработки в процессе сериализации и десериализации, должны реализовывать специальные методы с точными сигнатурами:

private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException; private void writeObject(java.io.ObjectOutputStream stream) throws IOException private void readObjectNoData() throws ObjectStreamException; 

Метод writeObject отвечает за запись состояния объекта для конкретного класса, чтобы соответствующий метод readObject смог восстановить его. Методу не нужно беспокоиться о состоянии, принадлежащем к суперклассам или подклассам объекта. Состояние сохраняется путем записи отдельных полей в ObjectOutputStream с помощью метода writeObject или с помощью методов для примитивных типов данных, поддерживаемых DataOutput.

Сериализация не записывает поля объектов, не реализующих интерфейс java.io.Serializable. Подклассы объектов, которые не являются сериализуемыми, могут быть сериализуемыми. В этом случае несериализуемый класс должен иметь конструктор no-arg, чтобы разрешить инициализацию его полей. В этом случае подкласс отвечает за сохранение и восстановление состояния несериализируемого класса. Часто бывает так, что поля этого класса доступны (открытые, пакетные или защищенные) или существуют методы get и set, которые можно использовать для восстановления состояния.

Сериализацию объекта можно предотвратить путем реализации методов writeObject и readObject, которые вызывают исключение NotSerializableException. Исключение будет перехвачено ObjectOutputStream и прервет процесс сериализации.

Реализация интерфейса Externalizable позволяет объекту взять на себя полный контроль над содержимым и форматом сериализованной формы объекта. Методы интерфейса Externalizable, writeExternal и readExternal, вызываются для сохранения и восстановления состояния объектов. При реализации классом они могут записывать и считывать собственное состояние с помощью всех методов ObjectOutput и ObjectInput. Объекты отвечают за обработку любого управления версиями.

Константы перечисления сериализуются иначе, чем обычные сериализуемые или внешние объекты. Сериализованная форма константы перечисления состоит исключительно из ее имени; значения полей константы не передаются. Для сериализации константы перечисления ObjectOutputStream записывает строку, возвращенную методом имени константы. Как и другие сериализуемые или внешние объекты, константы перечисления могут функционировать как целевые объекты обратных ссылок, которые впоследствии появляются в потоке сериализации. Невозможно настроить процесс сериализации констант перечисления; все методы writeObject и writeReplace, определенные типами перечисления, игнорируются во время сериализации. Аналогичным образом все объявления полей serialPersistentFields или serialVersionUID также игнорируются. Все типы перечисления имеют фиксированный serialVersionUID 0L.

Примитивные данные, за исключением сериализуемых полей и внешних данных, записываются в ObjectOutputStream в записях блочных данных. Запись блочных данных состоит из заголовка и данных. Заголовок данных блока состоит из маркера и количества байтов, следующих за заголовком. Последовательные записи примитивных данных объединяются в одну запись блочных данных. Коэффициент блокировки, используемый для записи блочных данных, будет составлять 1024 байта. Каждая запись блочных данных заполняется до 1024 байт или записывается всякий раз, когда режим блочных данных завершается. Вызовы методов ObjectOutputStream writeObject, defaultWriteObject и writeFields изначально завершают любую существующую запись блочных данных.

Добавлено в JDK1.1.

Части этой страницы являются изменениями, основанными на работе, созданной и совместно используемой проектом Android и используемой в соответствии с условиями, Creative Commons 2.5 Attribution License.

Конструкторы

Предоставьте возможность для подклассов, которые полностью повторно используют ObjectOutputStream, чтобы не выделять частные данные, только что используемые этой реализацией ObjectOutputStream.

Конструктор, используемый при создании управляемых представлений объектов JNI; вызывается средой выполнения.

Создает объект ObjectOutputStream, который выполняет запись в указанный выходной поток.

Свойства

Возвращает класс среды выполнения данного объекта Object .

Дескриптор базового экземпляра Android.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

Этот API поддерживает инфраструктуру Mono для Android и не предназначен для использования непосредственно из кода.

Этот API поддерживает инфраструктуру Mono для Android и не предназначен для использования непосредственно из кода.

Методы

Подклассы могут реализовать этот метод, чтобы данные класса могли храниться в потоке.

Подклассы могут реализовать этот метод для хранения пользовательских данных в потоке вместе с дескрипторами для динамических прокси-классов.

Создает и возвращает копию этого объекта.

Закрывает этот выходной поток и освобождает все системные ресурсы, связанные с этим потоком.

Запись нестатических и временных полей текущего класса в этот поток.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

Удалите все буферизированные данные в ObjectOutputStream.

Включите для потока замену объектов в потоке.

Указывает, равен ли какой-то другой объект этому объекту.

Сбрасывает этот выходной поток и принудительно записывает все буферизированные выходные байты.

Возвращает значение хэш-кода для объекта.

Вызывается сборщиком мусора для объекта , когда сборка мусора определяет, что больше нет ссылок на объект .

Пробуждение одного потока, ожидающего на мониторе этого объекта.

Активирует все потоки, ожидающие на мониторе этого объекта.

Извлеките объект , используемый для буферизации постоянных полей для записи в поток.

Этот метод позволяет доверенным подклассам ObjectOutputStream заменять один объект другим во время сериализации.

Сброс не учитывает состояние всех объектов, уже записанных в поток.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

Возвращает строковое представление объекта.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

Укажите версию протокола потока для использования при записи потока.

Заставляет текущий поток ждать, пока он не будет пробужден, как правило, из-за или .

Заставляет текущий поток ждать, пока он не будет пробужден, как правило, из-за em>, <>прерывания < или>em, либо до истечения определенного количества реального времени.

Заставляет текущий поток ждать, пока он не будет пробужден, как правило, из-за em>, <>прерывания < или>em, либо до истечения определенного количества реального времени.

Записывает байты b.length из указанного массива байтов в этот выходной поток.

Записывает байты len из указанного массива байтов, начиная со смещения off в этот выходной поток.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

Записывает логическое значение.

Записывает 8-разрядный байт.

Записывает строку в виде последовательности байтов.

Записывает 16-разрядную символь.

Записывает строку в виде последовательности символов char.

Запишите указанный дескриптор класса в ObjectOutputStream.

Записывает 64-разрядный двойник.

Запишите буферизированные поля в поток.

Записывает 32-разрядное значение float.

Записывает 32-разрядный int.

Записывает 64-разрядную длину.

Запишите указанный объект в ObjectOutputStream.

Метод, используемый подклассами для переопределения метода writeObject по умолчанию.

Записывает 16-разрядный короткий фрагмент.

Предоставляется метод writeStreamHeader, чтобы подклассы могли добавлять или добавлять в поток собственный заголовок.

Записывает объект unshared в ObjectOutputStream.

Примитивная запись данных этой строки в измененном формате UTF-8.

Явные реализации интерфейса

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

Методы расширения

Выполняет преобразование типа, проверенное средой выполнения Android.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

ObjectOutputStream записывает примитивные типы данных и графы объектов Java в OutputStream.

Сериализация объектов в Java

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

Стандартный механизм сериализации – интерфейс Serializable

Для сохранения объекта в Java, мы должны иметь сохраняемый объект. Объект делается сериализуемым путем реализации интерфейса java.io.Serializable, что значит для нижележащего API, что объект может быть сохранен в байтовом представлении и восстановлен в будущем Интерфейса Serializable – пустой интерфейс пометка, указывающий что объект серийный. Ниже приведен максимально простой пример его использования:

import java.io.Serializable; import java.util.Date; import java.util.Calendar; public class PersistentTime implements Serializable < private Date time; public PersistentTime() < time = Calendar.getInstance().getTime(); >public Date getTime() < return time; >>

Как вы можете видеть, единственным отличием от создания обычного класса является реализация интерфейса java.io.Serializable в строке 40. Полностью пустой интерфейс Serializable является маркером — это простое разрешение механизму сериализации проверять класс на возможность его сохранения. Таким образом, обратим внимание на первое правило сериализации: Следующий шаг — это, собственно, сохранение объекта. Это выполняется классом java.io.ObjectOutputStream. Этот класс является фильтрующим потоком — это надстройка над низкоуровневым потоком байтов (называемым узловым потоком) для работы с протоколом сериализации для нас. Узловые потоки могут быть использованы для записи в файловую систему или даже в сокет. Это означает, что мы можем легко передавать сохраняемый объект по сетевому кабелю и заново создавать его на другой машине! Посмотрите на код, используемый для сохранения объекта PersistentTime:

import java.io.ObjectOutputStream; import java.io.FileOutputStream; import java.io.IOException; public class FlattenTime < public static void main(String [] args) < String filename = "time.ser"; if(args.length >0) < filename = args[0]; >PersistentTime time = new PersistentTime(); FileOutputStream fos = null; ObjectOutputStream out = null; try < fos = new FileOutputStream(filename); out = new ObjectOutputStream(fos); out.writeObject(time); out.close(); >catch(IOException ex) < ex.printStackTrace(); >> >

Классы ObjectInputStream и ObjectOutputStream – обертки для потоков ввода/вывода с поддержкой записи и загрузки объектов. Интерфейс не зависит от платформы джава машины. Т.е. объект может быть создан на jvm одной платформы и без проблем загружен на другой.
Данных механизм может использоваться для сохранения состояния приложения или его части. А также для передачи объектов по сети. Реальная работа происходит на строке 20 когда мы вызываем метод ObjectOutputStream.writeObject() , который запускает механизм сериализации и объект сохраняется (в данном случае в файл). Для восстановления из файла мы можем использовать следующий код :

import java.io.ObjectInputStream; import java.io.FileInputStream; import java.io.IOException; import java.util.Calendar; public class InflateTime < public static void main(String [] args) < String filename = "time.ser"; if(args.length >0) < filename = args[0]; >PersistentTime time = null; FileInputStream fis = null; ObjectInputStream in = null; try < fis = new FileInputStream(filename); in = new ObjectInputStream(fis); time = (PersistentTime)in.readObject(); in.close(); >catch(IOException ex) < ex.printStackTrace(); >catch(ClassNotFoundException ex) < ex.printStackTrace(); >// напечатаем сохраненное время System.out.println("Flattened time: " + time.getTime()); System.out.println(); // напечатаем текущее время System.out.println("Current time: " + Calendar.getInstance().getTime()); > >

В коде выше, восстановление объекта происходит в строке 21 путем вызова метода ObjectInputStream.readObject() . Вызов метода считывает байты, которые мы предварительно сохранили, и создает объект, являющийся точной копией оригинала. Так как readObject() может прочитать любой сериализуемый объект, необходимо приведение к корректному типу. Это означает, что файл класса должен быть доступен из системы, в которой происходит восстановление .Другими словами, файл класса объекта и методы не сохраняются; сохраняется только состояние объекта. Позже, мы просто вызываем метод getTime() для получения времени, которое сохранил оригинальный объект. Зафиксированное время сравнивается с текущим для демонстрации того, что механизм сериализации работает так как ожидалось. Еще один пример сериализации объектов приведен ниже:

import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class CompanyInfoSerializeble implements Serializable < public String name; public String address; double lon, lat; @Override public String toString() < StringBuilder sb = new StringBuilder(); sb.append('<').append("name: ").append(name).append(", "); sb.append("address: ").append(address).append(", "); sb.append("location: (").append(lon).append(", ").append(lat) .append(')'); sb.append('>'); return sb.toString(); > // сохранение объекта - сериализация public static void demoSerialize(CompanyInfoSerializeble obj) < try < FileOutputStream fos = new FileOutputStream("test.data"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(obj); oos.close(); fos.close(); >catch (IOException e) < e.printStackTrace(); >> // загрузка объекта - десериализация public static CompanyInfoSerializeble demoDeserialize() < CompanyInfoSerializeble obj = null; try < FileInputStream fis = new FileInputStream("test.data"); ObjectInputStream ois = new ObjectInputStream(fis); obj = (CompanyInfoSerializeble) ois.readObject(); ois.close(); fis.close(); >catch (IOException i) < i.printStackTrace(); >catch (ClassNotFoundException c) < System.out.println("CompanyInfoSerializeble class not found"); c.printStackTrace(); >return obj; > public static void main(String[] args) < CompanyInfoSerializeble obj = new CompanyInfoSerializeble(); obj.name = "darkraha.com"; obj.address = "internet"; obj.lon=57.000; obj.lat=37.000; System.out.println("saved object: "+obj); demoSerialize(obj); CompanyInfoSerializeble obj2 = demoDeserialize(); System.out.println("loaded object: "+obj2); >>

Базовый механизм сериализации в Java прост в использовании, но здесь есть еще несколько вещей, которые нужно знать. Как упоминалось ранее, только объекты, реализующие Serializable могут быть сохранены. Класс java.lang.Object не реализовывает этот интерфейс. Поэтому, не все объекты в Java могут быть сохранены автоматически. Хорошей новостью является то, что большинство из них — такие как AWT и Swing GUI компоненты, строки и массивы — сериализуемы. Если среди членов класса есть ссылки на не серийные объекты, то при попытке сериализовать такой класс возникнет исключение NotSerializableException. С другой стороны, некоторые системные классы, такие как Thread, OutputStream и их подклассы, а также Socket несериализуемы. В действительности это не имеет никакого смысла. Например, поток, работающий в моей JVM может использовать память моей системы. Сохранение потока и попытка его запустить в вашей JVM не имеет смысла. Другим важным моментом в том, почему java.lang.Object не реализует интерфейс Serializable , является то, что любой создаваемый вами класс наследует только код Object (а не других сериализуемых классов), несериализуем до тех пор, пока вы не реализуете интерфейс самостоятельно (как сделано в предыдущем примере). В этой ситуации присутствует проблема: что если мы имеем класс, который содержит экземпляр класса Thread? В этом случае, можем ли мы когда-либо сохранить объект этого типа? Ответ утвердителен, пока вы сообщаете механизму сериализации наши намерения маркируя наш объект класса Thread как transient .

ключевое слово transient

Атрибут transient указывает, что указанный член класса должен игнорироваться механизмом сериализации. Полезно для секретных (пароль) или не особо важных данных. Пусть мы хотим создать класс, производящий анимацию. Я на самом деле не приведу здесь код анимации. Вот используемый класс:

import java.io.Serializable; public class PersistentAnimation implements Serializable, Runnable < transient private Thread animator; private int animationSpeed; public PersistentAnimation(int animationSpeed) < this.animationSpeed = animationSpeed; animator = new Thread(this); animator.start(); >public void run() < while(true) < // выполнение анимации >> >
  • Чтобы быть сохраняемым объект должен реализовывать интерфейс Serializable или наследовать его реализацию из его иерархии объектов.
  • Сохраняемый объект должен отмечать все несериализуемые поля модификатором transient

Другой пример использования transient: если в предыдущем примере о сериализации информации о компаниях изменить строку следующим образом:

transient public String address;

то в результате работы программы во второй строке вместо адреса будет null .

Модификация стандартного протокола: переопределение сериализации

Хотя код анимации выше демонстрирует, как нить может быть включена в объект, и при этом объект остается сериализуемым, существует серьезная проблема, если мы рассмотрим, как Java создает объекты. К сведению, когда мы создаем объект с помощью ключевого слова new, конструктор объекта вызывается только тогда, когда создается новый экземпляр класса. Сохраняя этот базовый факт в памяти, вернемся к нашему коду анимации. Сначала, мы создаем объект типа PersistentAnimation , который запускает нить анимации. Далее, мы сериализуем объект с помощью кода:

PersistentAnimation animation = new PersistentAnimation(10); FileOutputStream fos = . ObjectOutputStream out = new ObjectOutputStream(fos); out.writeObject(animation);

Все кажется правильным, пока мы считываем объект в вызове метода readObject() . Запомните, конструктор вызывается только при создании нового экземпляра. Мы не создаем здесь новый экземпляр, мы восстанавливаем сохраненный объект. В итоге объект анимации будет работать только один раз, при первом создании. Метод создания не сохраняется, не так ли?

Но есть и хорошие новости. Мы можем заставить наш объект работать так, как мы хотим; мы можем сделать рестарт анимации при восстановлении объекта. Чтобы сделать это, мы можем, например, создать вспомогательный метод startAnimation() , который делает то, что должен делать конструктор. Мы можем затем вызвать этот метод из конструктора, после чего мы считываем объект. Неплохо, но это приводит к увеличению сложности. Теперь, кто-то, кто хочет использовать этот объект анимации, будет знать какой метод нужно вызвать после обычного процесса десериализации. Это не делает механизм цельным, хотя Java API сериализации обещает это разработчикам.

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

  • writeObject – запись объекта в поток;
  • readObject – чтение объекта из потока;
  • writeReplace – позволяет заменить себя экземпляром другого класса перед записью;
  • readResolve – позволяет заменить на себя другой объект после чтения;

Эти методы объявлены (и должны быть объявлены) private, проверьте, что эти методы не уналедованы и не переопределены или не перегружены. Фокус в том, что виртуальная машина автоматически проверит, объявлены ли эти методы в течении вызова соответствующего метода. Виртуальная машина может вызывать private методы вашего класса когда она хочет, но другие объекты нет. Таким образом, целостность класса сохраняется и протокол сериализации может продолжить работу, как обычно. Протокол сериализации всегда используется тем же способом, путем вызова любого метода: ObjectOutputStream.writeObject() или ObjectInputStream.readObject() . Итак, хотя эти специализированные private методы предоставлены, сериализация объекта работает также по отношению к любому вызываемому объекту.

Принимая все это во внимание, посмотрим на исправленную версию PersistentAnimation который содержит эти private методы для предоставления нам контроля над процессом десериализаци, давая нам псевдоконструктор:

// пример из из SDN import java.io.Serializable; public class PersistentAnimation implements Serializable, Runnable < transient private Thread animator; private int animationSpeed; public PersistentAnimation(int animationSpeed) < this.animationSpeed = animationSpeed; startAnimation(); >public void run() < while(true) < // do animation here >> private void writeObject(ObjectOutputStream out) throws IOException < out.defaultWriteObject(); >private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException < // our "pseudo-constructor" in.defaultReadObject(); // now we are a "live" object again, so let's run rebuild and start startAnimation(); >private void startAnimation() < animator = new Thread(this); animator.start(); >>

Обратите внимание на первую строку каждого из новых private методов. Эти вызовы выполняют функцию, созвучную их названию — они выполняют стандартные запись и чтение сохраняемого объекта, что важно, так как мы не заменяли обычный процесс, мы только расширяли его. Эти методы работают, так как вызов ObjectOutputStream.writeObject() заставляет заработать протокол сериализации. Сначала объект проверяется на реализацию Serializable и затем проверяется, педоставлены ли эти private методы. Если они предоставлены, потоковый класс передается как параметр, давая контроль над его использованием.

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

Запрещаем сериализацию

Мы увидели простоту процесса сериализации, сейчас увидим несколько больше. Что если вы создаете класс, чей класс-предок сериализуем, но вы не хотите чтобы новый класс был сериализуемым? Вы не можете убрать реализацию интерфейса, следовательно если ваш класс-предок реализовал Serializable , ваш новый класс реализовывает его тоже (объединение двух правил, приведенных выше). Для прекращения автоматической сериализации, вы снова однажды можете использовать private методы для генерации исключения NotSerializableException . Здесь показано, как это можно сделать:

private void writeObject(ObjectOutputStream out) throws IOException < throw new NotSerializableException("Не сегодня!"); >private void readObject(ObjectInputStream in) throws IOException

Любая попытка записи или чтения этого объекта всегда будет генерировать исключение. Запомните, так как эти методы объявлены как private, никто не может изменить ваш код без наличия доступных исходных текстов — Java не допускает перекрытие этих методов.

Создание вашего собственного механизма сериализации: интерфейс Externalizable

Также есть возможность определить полностью свой механизм сериализации. Для нужно реализовать интерфейс Externalizable вместо Serializable . Этот интерфейс содержит два метода:

  • public void writeExternal(ObjectOutput out) throws IOException;
  • public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;

Переопределите эти методы для предоставления вашего протокола. В отличие от предыдущих двух вариантов сериализации, здесь ничего не предоставляется. Следовательно, протокол полностью в ваших руках. Несмотря на то, что это более сложный сценарий, он также наиболее контролируемый. Пример ситуации для альтернативного типа сериализации: чтение и запись PDF файлов в Java приложении. Если вы знаете как писать и читать PDF файлы (необходимую последовательность байтов), вы можете предоставить PDF-специфичный протокол в методах writeExternal и readExternal .

Однако, как и ранее, здесь нет различия в том, какая реализация Externalizable используется классом. Только вызовите writeObject() или readObject и, вуаля, эти методы интерфейса Externalizable будут вызваны автоматически.

Подводные камни сериализации

Имеются некоторые подводные камни механизма сериализации, которые могут выглядеть очень странно для неподготовленных разработчиков. Цель этой статьи — подготовить вас! – поговорим о некоторых затруднениях и посмотрим, почему они существуют и как их обрабатывать.

Кэширование объектов в потоке

Сначала рассмотрим ситуацию в которой объект записан в поток и затем записывается снова. По умолчанию, ObjectOutputStream будет сохранять ссылку на объект, записанный в него. Это значит, что если состояние записанного объекта записано и затем записано снова, тогда новое состояние объекта не будет сохранено! Здесь кусок кода, показывающий эту проблему в действии:

ObjectOutputStream out = new ObjectOutputStream(. ); MyObject obj = new MyObject(); //должен реализовывать интерфейс Serializable obj.setState(100); out.writeObject(obj); // сохраняет объект с состоянием = 100 obj.setState(200); out.writeObject(obj); // не сохраняет новое состояние объекта

Имеется два пути для контроля этой ситуации. Первый, вы можете всегда закрывать поток после записи, гарантируя, что каждый раз записывается новый объект. Второй, вы можете вызвать метод ObjectOutputStream.reset() , который скажет потоку освободить кэш ссылок, которые он содержит, и по новому запросу на запись она будет действительно производиться. Будте внимательны, метод reset сбрасывает весь кэш объектов, значит все записанные объекты могут быть перезаписанны.

Контроль версий

Представьте, что вы создали класс, создали его экземпляр, и записали его в поток объектов. Этот сохраненный объект некоторое время находится в файловой системе. Тем временем, вы обновили файл класса, возможно добавили новое поле. Что произойдет, когда вы попытаетесь прочитать сохраненный объект?

Плохой новостью является то, что будет выработано исключение — java.io.InvalidClassException — так как все классы с возможностью сохраненияe автоматически получают уникальный идентификатор. Если идентификатор класса не совпадает с идентификатором сохраненного объекта, генерируется исключительная ситуация. Однако, если вы задумаетесь, почему будет вызвано исключение только из-за того, что я добавил поле? Почему полю не может быть присвоено значение по умолчанию и потом записано в следующий раз?

Да, это возможно, но потребуются небольшие манипуляции с кодом. Идентификатор, являющийся частью всех классов содержится в поле serialVersionUID . Если вы хотите контролировать версионность, вы просто подставляете поле serialVersionUID вручную и обеспечиваете ее постоянство при изменениях, вносимых в класс. Вы можете использовать утилиту serialver, поставляемую с дистрибутивом JDK, для просмотра кода по-умолчанию (по-умолчанию это хэш-код объекта).

Пример использования serialver с классом с именем Baz :

> serialver Baz > Baz: static final long serialVersionUID = 10275539472837495L;

Просто скопируйте возвращенную строку с идентификатором версии и вставьте ее в ваш код. (В Windows, вы можете запустить эту утилиту с параметром -show для упрощения процедуры копирования и вставки.) Теперь, если вы вносите любые изменения в класс Baz, удостоверьтесь что указан тот же идентификатор версии и все будет в порядке.

Контроль версий работает отлично пока изменения совместимы. Совместимым изменением является добавление или удаление метода или поля. Несовместимыим изменениями являются изменение иерархии объектов или удаление реализации интерфейса Serializable. Полный список совместимых и несовместимых изменений приведен в спцификации Java сериализации (смотри Ресурсы).
Рассмотрение производительности

Наше третье затруднение: стандартный механизм, несмотря на простоту использования, не лучший исполнитель. Я записывал объект Date в файл 1000 раз, повторив эту процедуру 100 раз. Среднее время записи объекта Date было 115 милисекунд. Затем я записал вручную объект Date , используя стандартные способы ввода/вывода и то же количество итераций; среднее время было 52 милисекунды. Почти половина времени! Здесь часто возникает противоречие между удобством и производительностью, и сериализация не доказывает обратного. Если в первую очередь принимать во внимание скорость для вашего приложения, вы можете подумать о создании своего протокола.

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

Класс Java.io.ObjectOutputStream

Класс Java.io.ObjectOutputStream записывает примитивные типы данных и графики объектов Java в OutputStream. Объекты могут быть прочитаны (восстановлены) с помощью ObjectInputStream.

Объявление класса

Ниже приводится объявление для класса Java.io.ObjectOutputStream:

public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants

Конструкторы классов

защищенный ObjectOutputStream ()

Это обеспечивает способ для подклассов, которые полностью переопределяют ObjectOutputStream, чтобы не выделять частные данные, только используемые этой реализацией ObjectOutputStream.

ObjectOutputStream (OutputStream out)

Это создает ObjectOutputStream, который записывает в указанный OutputStream.

защищенный ObjectOutputStream ()

Это обеспечивает способ для подклассов, которые полностью переопределяют ObjectOutputStream, чтобы не выделять частные данные, только используемые этой реализацией ObjectOutputStream.

ObjectOutputStream (OutputStream out)

Это создает ObjectOutputStream, который записывает в указанный OutputStream.

Методы класса

Sr.No. Метод и описание
1 Защищенный void annotateClass (Class cl)

Подклассы могут реализовать этот метод, чтобы позволить данным класса быть сохраненными в потоке.

Подклассы могут реализовывать этот метод для хранения пользовательских данных в потоке вместе с дескрипторами для динамических прокси-классов.

Этот метод закрывает поток.

Этот метод записывает в этот поток нестатические и непереходные поля текущего класса.

Этот метод истощает любые буферизованные данные в ObjectOutputStream.

Этот метод позволяет потоку выполнять замену объектов в потоке.

Этот метод очищает поток.

Этот метод извлекает объект, используемый для буферизации постоянных полей для записи в поток.

Этот метод позволит доверенным подклассам ObjectOutputStream заменять один объект другим во время сериализации.

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

Этот метод указывает версию протокола потока для использования при записи потока.

Этот метод записывает массив байтов.

Этот метод записывает вложенный массив байтов.

Этот метод записывает байт.

Этот метод записывает логическое значение.

Этот метод записывает 8-битный байт.

Этот метод записывает строку в виде последовательности байтов.

Этот метод записывает 16-битный символ.

Этот метод записывает String как последовательность символов.

Этот метод записывает указанный дескриптор класса в ObjectOutputStream.

Этот метод записывает 64-битный дубль.

Этот метод записывает буферизованные поля в поток.

Этот метод записывает 32-разрядное число с плавающей точкой.

Этот метод записывает 32-битное int.

Этот метод записывает 64-битную длину.

Этот метод записывает указанный объект в ObjectOutputStream.

Этот метод используется подклассами для переопределения метода writeObject по умолчанию.

Этот метод записывает 16-битное сокращение.

Этот метод предоставляется, чтобы подклассы могли добавлять или добавлять свой собственный заголовок в поток.

Этот метод записывает «неразделенный» объект в ObjectOutputStream.

Подклассы могут реализовать этот метод, чтобы позволить данным класса быть сохраненными в потоке.

Подклассы могут реализовывать этот метод для хранения пользовательских данных в потоке вместе с дескрипторами для динамических прокси-классов.

Этот метод закрывает поток.

Этот метод записывает в этот поток нестатические и непереходные поля текущего класса.

Этот метод истощает любые буферизованные данные в ObjectOutputStream.

Этот метод позволяет потоку выполнять замену объектов в потоке.

Этот метод очищает поток.

Этот метод извлекает объект, используемый для буферизации постоянных полей для записи в поток.

Этот метод позволит доверенным подклассам ObjectOutputStream заменять один объект другим во время сериализации.

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

Этот метод указывает версию протокола потока для использования при записи потока.

Этот метод записывает массив байтов.

Этот метод записывает вложенный массив байтов.

Этот метод записывает байт.

Этот метод записывает логическое значение.

Этот метод записывает 8-битный байт.

Этот метод записывает строку в виде последовательности байтов.

Этот метод записывает 16-битный символ.

Этот метод записывает String как последовательность символов.

Этот метод записывает указанный дескриптор класса в ObjectOutputStream.

Этот метод записывает 64-битный дубль.

Этот метод записывает буферизованные поля в поток.

Этот метод записывает 32-разрядное число с плавающей точкой.

Этот метод записывает 32-битное int.

Этот метод записывает 64-битную длину.

Этот метод записывает указанный объект в ObjectOutputStream.

Этот метод используется подклассами для переопределения метода writeObject по умолчанию.

Этот метод записывает 16-битное сокращение.

Этот метод предоставляется, чтобы подклассы могли добавлять или добавлять свой собственный заголовок в поток.

Этот метод записывает «неразделенный» объект в ObjectOutputStream.

Методы унаследованы

Этот класс наследует методы от следующих классов –

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *