- Русские Блоги
- Android два метода сериализации Serializable и Parcelable
- Что такое сериализация
- Сериализуемый интерфейс
- serialVersionUID
- Сериализация и десериализация Serializable
- Parcelable интерфейс
- подводить итоги
- 1. Что такое сериализация и десериализация?
- (1) Объяснение терминов
- (2) Подробное объяснение сериализации
- Во-вторых, чем отличается Java-объект от сериализации Java-объекта?
- 3. Зачем использовать сериализацию и десериализацию?
- 4. В чем разница между Serializable и Parcelable в Android?
- Пять, пример Parcelable
- Шесть, принцип посылки
- Семь, сериализация и десериализация Parcelable эксперимент?
- Сериализация в Java
- Зачем сериализация нужна?
- Как сериализовать объект?
- Формат сериализованного объекта
- Алгоритм сериализации Java
- Заключение
- Об авторе
Русские Блоги
Android два метода сериализации Serializable и Parcelable
Что такое сериализация
Мы всегда говорим или слышим о «сериализации». Каково ее определение?
Сериализация (сериализация) Процесс преобразования информации о состоянии объекта в форму, которая может быть сохранена или передана. Во время сериализации объект записывает свое текущее состояние во временное или постоянное хранилище. Позже вы можете воссоздать объект, прочитав или десериализуя состояние объекта из области хранения.
Двоичная сериализация поддерживает точность типов, что полезно для сохранения состояния объектов между различными вызовами приложения. Например, сериализуя объект в буфер обмена, вы можете использовать его в разных приложениях. Вы можете сериализовать объекты в потоки, диски, память, сети и т. Д. Удаленное взаимодействие использует сериализацию для передачи объектов между компьютерами или доменами приложений «по значению».
Проще говоря, «сериализация» — это преобразование состояния объекта во время выполнения в двоичное, а затем сохранение его в потоке, в памяти или передача на другие терминалы по сети.
В разработке под Android мы часто используем Intent при передаче данных в компонентах. При передаче данных нам необходимо передать Serializable или Parcelable данные, такие как метод Intent.putExtra:
Binder также будет использоваться для передачи данных.
Сегодня я представлю эти два метода сериализации.
Сериализуемый интерфейс
Serializable — это интерфейс сериализации, предоставляемый Java, это пустой интерфейс:
Serializable используется для идентификации текущего класса, может быть ObjectOutputStream Сериализация и бытие ObjectInputStream Десериализация.
Serializable имеет следующие характеристики:
- В сериализуемом классе состояние атрибута, которое не реализует Serializable, не может быть сериализовано / десериализовано
- Другими словами, в процессе десериализации класса его несериализуемые свойства будут воссозданы путем вызова конструктора без параметров.
- Следовательно, конструктор без параметров этого свойства должен быть доступен, иначе во время выполнения будет сообщено об ошибке.
- Класс, реализующий сериализацию, и его подклассы также сериализуемы.
Ниже приведен класс сущности, реализующий Serializable:
Видно, что реализация Serializable очень проста, за исключением содержимого сущности, просто создайте его serialVersionUID Атрибуты в порядке.
serialVersionUID
По названию видно, что это serialVersionUID Что-то похожее на наш обычный номер версии интерфейса, который однозначно определяет сериализуемый класс во время выполнения.
Другими словами, когда класс сериализуется, его номер версии будет сохранен во время выполнения, а затем во время десериализации проверьте, совпадает ли номер версии объекта, который вы хотите десериализовать. Если он не согласован, будет сообщено об ошибке: · InvalidClassException 。
Если мы не создадим этот номер версии сами, среда выполнения вычислит номер версии по умолчанию на основе многих характеристик класса в процессе сериализации. Однако, если вы немного измените этот класс, номер версии изменится. Если это произойдет после сериализации, это вызовет вышеупомянутую ошибку во время десериализации.
Поэтому спецификация JVM настоятельно рекомендует объявлять номер версии вручную. Это число может быть случайным, если оно фиксировано. В то же время лучше оставаться конфиденциальным и окончательным и постараться сохранить его неизменным.
Кроме того, статические и временные измененные атрибуты не сохраняются в процессе сериализации. Первый хорошо понятен, потому что статические атрибуты управляются классом и не принадлежат состоянию объекта; в то время как последний является ключевым словом Java, специально используемым для идентификации непоследовательности. Атрибуты.
Реализация Serializable по умолчанию не будет создана автоматически. serialVersionUID Атрибут, чтобы напоминать нам создавать вовремя serialVersionUID , Можно поискать в настройках serializable Затем выберите несколько вариантов, как показано на рисунке ниже, для тех, кто не заявил serialVersionUID Добавьте предупреждение для классов атрибутов и внутренних классов.
Поэтому, когда мы создаем класс без объявления атрибута UID, на имени класса будет желтое предупреждение:
Содержимое предупреждения будет отображаться при наведении на него мыши:
GroupBean’ does not define a ‘serialVersionUID’ field less… (Ctrl+F1)
Reports any Serializable classes which do not provide a serialVersionUID field. Without a serialVersionUID field, any change to a class will make previously serialized versions unreadable.
В это время мы можем сгенерировать serialVersionUID, нажав комбинацию клавиш для запроса кода.
Сериализация и десериализация Serializable
Сериализация и десериализация Serializable выполняются через ObjectOutputStream и ObjectInputStream соответственно. Пример кода выглядит следующим образом:
Parcelable интерфейс
Parcelable — это интерфейс сериализации, уникальный для Android:
Классы, реализующие интерфейс Parcelable, будут преобразованы в при сериализации и десериализации. Parcel Тип данных.
Parcel является носителем, он может содержать ссылки на данные или объекты, а затем передаваться между процессами через IBinder.
Класс, реализующий интерфейс Parcelable, должен иметь статическую переменную типа CREATOR. Ниже приведен пример:
подводить итоги
Как видите, использование Serializable относительно просто, просто создайте номер версии; хотя Parcelable относительно сложен, необходимо реализовать четыре метода.
Как правило, рекомендуется использовать Serializable при сохранении данных на SD-карту или передаче по сети.Хотя эффективность ниже, им легко пользоваться.
Рекомендуется использовать Parcelable для передачи данных во время выполнения, например Intent, Bundle и т. Д. Нижний уровень Android оптимизирован для обеспечения высокой эффективности.
Thanks
Перевод с: https://blog.csdn.net/u011240877/article/details/72455715
1. Что такое сериализация и десериализация?
(1) Объяснение терминов
Сериализация объекта: процесс преобразования объекта Java в байтовую последовательность и сохранения его на носителе.
Десериализация объектов: процесс восстановления последовательностей байтов в объекты Java.
(2) Подробное объяснение сериализации
Сериализация объектов включает три ключевых момента: объекты Java, последовательности байтов и хранилище.
1. Каков состав объектов Java?
Объекты Java содержат переменные и методы. Но сериализация и десериализация имеют дело только с переменными Java, а не с методами, а сериализация и десериализация имеют дело только с данными.
2. Что такое последовательность символов?
Последовательность символов состоит из двух слов, символ находится в поле компьютера и связи, а символ является единицей информации. Математически последовательность — это объект (или событие), расположенный в ряд.
«Персонажи-Википедия» ,«Последовательность-Википедия»Грубо говоря, это набор из нескольких последовательно расположенных персонажей. Похожие на «1A165613246546»
3. Магазин
Последовательность символов необходимо сохранить в одном месте, которым может быть жесткий диск или память.
Проще говоря: сериализация сохраняет информацию о текущем объекте. Десериализация — прямо противоположная операция.
Во-вторых, чем отличается Java-объект от сериализации Java-объекта?
Предпосылка для существования объектов Java должна существовать во время работы JVM.Если вы хотите получить указанный объект Java, когда JVM не запущена или на JVM другой машины, это невозможно выполнить в рамках существующего механизма объектов Java.
В отличие от объектов Java, если вы выполняете операции сериализации над объектами Java, поскольку принцип заключается в сохранении информации об объекте Java на носителе, вы можете использовать два типа объектов Java, которые не могут существовать. В этом случае объекты Java все еще можно использовать.
3. Зачем использовать сериализацию и десериализацию?
Основываясь на вышеупомянутом понимании сериализации и десериализации, этот вопрос можно перевести на вопрос: почему мне нужно сохранять информацию об объекте на носителе данных и читать ее позже?
Из-за объяснения во втором случае необходимо получить указанный объект Java, когда JVM не запущена или на JVM других машин.
1. Используйте RMI (удаленный вызов метода)
2. Передача объектов в сети (Java Beans)
3. Глубокая копия объекта (включая сеть отношений между объектами, содержащуюся в текущем объекте)
4. В чем разница между Serializable и Parcelable в Android?
Оба используются для поддержки операций сериализации и десериализации. Самая большая разница между ними — это разница в носителях. Serializable использует ввод-вывод для чтения, записи и хранения на жестком диске, тогда как Parcelable читает и записывает непосредственно в память. Очевидно, что память Скорость чтения и записи обычно выше, чем у ввода-вывода, поэтому в Android обычно предпочтительнее использовать Parcelable.
Сериализуемость не в центре внимания, но вы можете проверить«Анализ алгоритмов сериализации Java»В этой статье реализован простой пример Serializable: просмотрите файл ввода-вывода, сгенерированный сериализацией, прочтите его в шестнадцатеричном формате и по очереди объясните значение каждого шестнадцатеричного числа.
Пять, пример Parcelable
Класс, реализующий интерфейс Parcelable в Android, может поддерживать последовательность и десериализацию. Ниже приведен пример реализации:
1. Реализуйте интерфейс Parcelable.
2. Добавьте атрибуты сущности
3. Переопределите метод writeToParcel (Parcel dest, int flags), чтобы указать данные, которые будут записаны в класс Parcel.
4. Создайте статический объект Parcelable.Creator, есть два метода createFromParcel (Parcel in) и newArray (int size), первый указывает, как читать объекты данных из Parcel, второй создает Массив.
5. Переопределите метод describeContents и верните 0 по умолчанию.
public class Gril implements Parcelable <
private int mAge; // возраст
private boolean mSexy; // Это сексуально
public void writeToParcel(Parcel dest, int flags) <
dest.writeByte((byte) (mSexy ? 1 : 0));
public static final Parcelable.Creator CREATOR = new Parcelable.Creator () <
public Gril createFromParcel(Parcel in) <
Gril gril = new Gril();
gril.mSexy = in.readByte() != 0;
public Gril[] newArray(int size) <
return new Gril[size];
public int describeContents() <
Шесть, принцип посылки
Как видно из приведенного выше примера, конкретная запись (dest.writeInt (mAge);) и чтение (gril.mAge = in.readInt ();) — это все операции, выполняемые над объектом Parcel, опубликованным ниже. Это определение Parcle для чтения и записи данных типа int.
public final class Parcel <
* Write an integer value into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
public final native void writeInt(int val);
* Read an integer value from the parcel at the current dataPosition().
public final native int readInt();
Из приведенного выше кода видно, что все описания собственных методов используют JNI, а конкретное местоположение — system / frameworks / base / core / jni / android_util_Binder.cpp. Далее также в качестве примера используется чтение и запись типа int.
static void android_os_Parcel_writeInt(JNIEnv* env, jobject clazz, jint val)
Parcel* parcel = parcelForJavaObject(env, clazz);
if (parcel != NULL) <
const status_t err = parcel->writeInt32(val);
if (err != NO_ERROR) <
jniThrowException(env, «java/lang/OutOfMemoryError», NULL);
static jint android_os_Parcel_readInt(JNIEnv* env, jobject clazz)
Parcel* parcel = parcelForJavaObject(env, clazz);
if (parcel != NULL) <
Из вышеизложенного видно, что вызывается реализация Parcel и вызываются функции writeInt32 и readInt32 соответственно, а затем давайте посмотрим на конкретную реализацию. Расположение: /system/frameworks/base/libs/binder/Parcel.cpp
status_t Parcel::writeInt32(int32_t val)
status_t Parcel::writeAligned(T val) <
*reinterpret_cast (mData+mDataPos) = val;
status_t err = growData(sizeof(val));
if (err == NO_ERROR) goto restart_write;
status_t Parcel::readInt32(int32_t *pArg) const
status_t Parcel::readAligned(T *pArg) const <
const void* data = mData+mDataPos;
*pArg = *reinterpret_cast (data);
Следующие 4 балла взяты из«Изучение механизма отправки посылок в Android (часть 1)»
Заинтересованные друзья могут прочитать его сами. Это несложно понять. Вот краткое изложение основных идей:
1. Все чтение и запись выполняются в памяти, в основном с помощью malloc (), realloc (), memcpy () и других операций с памятью, поэтому это более эффективно, чем использование external в сериализации JAVA. Память будет намного выше;
2. При чтении и записи он выравнивается по 4 байтам, вы можете видеть, что #define PAD_SIZE (s) (((s) +3) &
3) выполняет определение макроса это дело;
3. Если предварительно выделенного места недостаточно, newSize = ((mDataSize + len) * 3) / 2; сразу выделит на 50% больше;
4. Для обычных данных используется адрес памяти mData, а для данных типа IBinder и FileDescriptor используется адрес памяти mObjects. Последнее достигается с помощью flatten_binder () и unflatten_binder (), цель состоит в том, что объект, прочитанный во время десериализации, является исходным объектом без необходимости обновлять новый объект.
Семь, сериализация и десериализация Parcelable эксперимент?
Источник
Сериализация в Java
Зачем сериализация нужна?
В сегодняшнем мире типичное промышленное приложение будет иметь множество компонентов и будет распространено через различные системы и сети. В Java всё представлено в виде объектов; Если двум компонентам Java необходимо общаться друг с другом, то им необходим механизм для обмена данными. Есть несколько способов реализовать этот механизм. Первый способ это разработать собственный протокол и передать объект. Это означает, что получатель должен знать протокол, используемый отправителем для воссоздания объекта, что усложняет разработку сторонних компонентов. Следовательно, должен быть универсальный и эффективный протокол передачи объектов между компонентами. Сериализация создана для этого, и компоненты Java используют этот протокол для передачи объектов.
Рисунок 1 демонстрирует высоко-уровневое представление клиент-серверной коммуникации, где объект передаётся с клиента на сервер посредством сериализации.
Рисунок 1.
Как сериализовать объект?
Для начала следует убедиться, что класс сериализуемого объекта реализует интерфейс java.io.Serializable как показано в листинге 1.
class TestSerial implements Serializable <
public byte version = 100;
public byte count = 0;
>
* This source code was highlighted with Source Code Highlighter .
В Листинге 1 только одна вещь отличается от создания нормального класса, это реализация интерфейса java.io.Serializable . Интерфейс Serializable это интерфейс-маркер; в нём не задекларировано ни одного метода. Но говорит сериализующему механизму, что класс может быть сериализован.
Теперь у нас есть всё необходимое для сериализации объекта, следующим шагом будет фактическая сериализация объекта. Она делается вызовом метода writeObject() класса java.io.ObjectOutputStream , как показано в листинге 2.
public static void main( String args[]) throws IOException <
FileOutputStream fos = new FileOutputStream( «temp.out» );
ObjectOutputStream oos = new ObjectOutputStream(fos);
TestSerial ts = new TestSerial();
oos.writeObject(ts);
oos.flush();
oos.close();
>
* This source code was highlighted with Source Code Highlighter .
В листинге 2 показано сохранение состояния экземпляра TestSerial в файл с именем temp.out
Для воссоздания объекта из файла, необходимо применить код из листинга 3.
public static void main( String args[]) throws IOException <
FileInputStream fis = new FileInputStream( «temp.out» );
ObjectInputStream oin = new ObjectInputStream(fis);
TestSerial ts = (TestSerial) oin.readObject();
System. out .println( «version=» +ts.version);
>
* This source code was highlighted with Source Code Highlighter .
Восстановление объекта происходит с помощью вызова метода oin.readObject() . В методе происходит чтение набора байт из файла и создаие точной копии графа оригинального объекта. oin.readObject() может прочитать любой сериализованный объект, поэтому необходимо полученный объект приводить к конкретному типу.
Выполненный код выведет version=100 в стандартный вывод.
Формат сериализованного объекта
Как должен выглядеть сериализованный объект? Вспомните простой код из предыдущего раздела, который сериализует объект класса TestSerial и записывает в temp.out . В листинге 4 показано содержимое файла temp.out , в шестнадцатеричном виде.
AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65
73 74 A0 0C 34 00 FE B1 DD F9 02 00 02 42 00 05
63 6F 75 6E 74 42 00 07 76 65 72 73 69 6F 6E 78
70 00 64
Если вы снова посмотрите на TestSerial , то увидите, что у него всего 2 байтовых члена. Как показано в листинге 5.
public byte version = 100;
public byte count = 0;
* This source code was highlighted with Source Code Highlighter .
Размер байтовой переменной один байт, и следовательно полный размер объекта (без заголовка) — два байта. Но размер сериализованного объекта 51 байт. Удивлены? Откуда взялись эти дополнительные байты и что они обозначают? Они добавлены сериализующим алгоритмом и необходимы для воссоздания объекта. В следующем абзаце будет подробно описан этот алгоритм.
Алгоритм сериализации Java
К этому моменту у вас уже должно быть достаточно знаний, чтобы сериализовать объект. Но как работает этот механизм? Алгоритм сериализации делает следующие вещи:
- запись метаданных о классе ассоциированном с объектом
- рекурсивная запись описания суперклассов, до тех пор пока не будет достигнут java.lang.object
- после окончания записи метаданных начинается запись фактических данных ассоциированных с экземпляром, только в этот раз начинается запись с самого верхнего суперкласса
- рекурсивная запись данных ассоциированных с экземпляром начиная с самого низшего суперкласса
В листинге 6 указан пример охватывающий все возможные случаи сериализации
class parent implements Serializable <
int parentVersion = 10;
>
class contain implements Serializable <
int containVersion = 11;
>
public class SerialTest extends parent implements Serializable <
int version = 66;
contain con = new contain();
public int getVersion() <
return version;
>
public static void main( String args[]) throws IOException <
FileOutputStream fos = new FileOutputStream( «temp.out» );
ObjectOutputStream oos = new ObjectOutputStream(fos);
SerialTest st = new SerialTest();
oos.writeObject(st);
oos.flush();
oos.close();
>
>
* This source code was highlighted with Source Code Highlighter .
В примере сериализуется объект класса SerialTest , который наследуется от parent и содержит объект-контейнер класса contain . В листинге 7 показан сериализованный объект.
AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65
73 74 05 52 81 5A AC 66 02 F6 02 00 02 49 00 07
76 65 72 73 69 6F 6E 4C 00 03 63 6F 6E 74 00 09
4C 63 6F 6E 74 61 69 6E 3B 78 72 00 06 70 61 72
65 6E 74 0E DB D2 BD 85 EE 63 7A 02 00 01 49 00
0D 70 61 72 65 6E 74 56 65 72 73 69 6F 6E 78 70
00 00 00 0A 00 00 00 42 73 72 00 07 63 6F 6E 74
61 69 6E FC BB E6 0E FB CB 60 C7 02 00 01 49 00
0E 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E 78
70 00 00 00 0B
На рисунке 2 показан сценарий алгоритма сериализации.
Рисунок 2.
Давайте рассмотрим, что собой представляет каждый байт в сериализованном объекте. В начале идёт информация о протоколе сериализации:
- AC ED: STREAM_MAGIC . Говорит о том, что используется протокол сериазизации.
- 00 05: STREAM_VERSION . Версия сериализации.
- 0x73: TC_OBJECT . Обозначение нового объекта.
На первом шаге алгоритм сериализации записывает описание класса ассоциированного с объектом. В примере был сериализован объект класса SerialTest , следовательно алгоритм начал записывать описание класса SerailTest .
- 0x72: TC_CLASSDESC . Обозначение нового класса.
- 00 0A : Длина имени класса.
- 53 65 72 69 61 6c 54 65 73 74: SerialTest , имя класса.
- 05 52 81 5A AC 66 02 F6: SerialVersionUID , идентификатор класса.
- 0x02 : Различные флаги. Этот специфический флаг говорит о том, что объект поддерживает сериализацию.
- 00 02 : Число полей в классе.
Теперь алгоритм записывает поле int version = 66; .
- 0x49 : Код типа поля. 49 это «I», которое закреплено за Int.
- 00 07 : Длина имени поля.
- 76 65 72 73 69 6F 6E: version , имя поля.
Затем алгоритм записывает следующее поле, contain con = new contain(); . Это объект следовательно будет записано каноническое JVM обозначение этого поля.
- 0x74: TC_STRING . Обозначает новую строку.
- 00 09 : Длина строки.
- 4C 63 6F 6E 74 61 69 6E 3B: Lcontain; , Каноническое JVM обозначаение.
- 0x78: TC_ENDBLOCKDATA , Конец опционального блока данных для объекта.
Следующим шагом алгоритма является запись описания класса parent , который является непосредственным суперклассом для SerialTest .
- 0x72: TC_CLASSDESC . Обозначение нового класса.
- 00 06 : Длина имени класса.
- 70 61 72 65 6E 74: parent , имя класса
- 0E DB D2 BD 85 EE 63 7A: SerialVersionUID , идентификатор класса.
- 0x02 : Различные флаги. Этот флаг обозначает что класс поддерживает сериализацию.
- 00 01 : Число полей в классе.
Теперь алгоритм записывает описание полей класса parent , класс имеет одно поле, int parentVersion = 100; .
- 0x49 : Код типа поля. 49 обозначает «I», которое закреплено за Int.
- 00 0D : Длина имени поля.
- 70 61 72 65 6E 74 56 65 72 73 69 6F 6E : parentVersion, имя поля.
- 0x78: TC_ENDBLOCKDATA , конец опционального блока данных для объекта.
- 0x70: TC_NULL , обозначает то что больше нет суперклассов, потому что мы достигли верха иерархии классов.
До этого алгоритм сериализации записывал описание классов ассоциированных с объектом и всех его суперклассов. Теперь будут записаны фактические данные ассоциированные с объектом. Сначала записываются члены класса parent :
- 00 00 00 0A: 10 , Значение parentVersion .
Дальше перемещаемся в SerialTest
- 00 00 00 42: 66 , Значение version .
Следующие несколько байт очень интересны. Алгоритму необходимо записать информацию объекте класса contain .
* This source code was highlighted with Source Code Highlighter .
Заключение
В этой статье вы увидели как сериализовать объект, и узнали как работает алгоритм сериализации. Я надеюсь эта статья помогла вам лучше понять что происходит, когда вы сериализуете объект.
Об авторе
Sathiskumar Palaniappan имеет более чем 4-х летний опыт работы в IT-индестрии, и работает с Java технологиями более 3 лет. На данный момент он работает system software engineer в Java Technology Center, IBM Labs. Также имеет опыт работы в телекоммуникационной индустрии.
Источник