Открыть сервис

Serializable

Serializable — это свойство объекта или структуры данных, позволяющее преобразовывать его состояние в последовательный поток байтов (сериализовать) для последующего сохранения, передачи по сети или восстановления (десериализации). Термин широко используется в программировании, базах данных и распределённых системах. Объект, реализующий интерфейс или обладающий атрибутом, помечающим его как сериализуемый, называется сериализуемым.

История

Понятие сериализации возникло в ранних языках программирования, таких как Smalltalk (1970-е годы), где объекты могли быть сохранены в файл. В 1990-х годах с развитием распределённых вычислений и удалённого вызова процедур (RPC) сериализация стала ключевой технологией. В 1995 году в языке Java был введён интерфейс Serializable (пакет java.io), который позволял объектам автоматически сериализоваться в байтовый поток. В 2000-х годах с появлением веб-сервисов и XML/REST-API сериализация стала использоваться для обмена данными в форматах JSON, XML, YAML. В 2010-х годах с развитием микросервисной архитектуры и NoSQL-баз данных (например, MongoDB, Redis) сериализация стала неотъемлемой частью хранения и передачи данных.

Классификация

По способу реализации

  • Встроенная сериализация — реализуется средствами языка программирования (например, Serializable в Java, BinaryFormatter в .NET, pickle в Python). Требует минимальных усилий от разработчика, но может быть неэффективной или небезопасной.
  • Ручная сериализация — разработчик самостоятельно определяет, какие поля и как преобразовывать в байты (например, через методы writeObject/readObject в Java, __getstate__/__setstate__ в Python). Позволяет оптимизировать производительность и контролировать безопасность.
  • Сериализация через библиотеки — использование сторонних библиотек (например, Jackson для JSON в Java, protobuf от Google, MessagePack). Обеспечивает кроссплатформенность, сжатие и скорость.

По формату данных

  • Бинарная сериализация — данные преобразуются в компактный двоичный формат (например, Java Serialization, Protocol Buffers, Avro, Thrift). Эффективна по размеру и скорости, но нечитаема человеком.
  • Текстовая сериализация — данные представляются в виде строк (например, JSON, XML, YAML, CSV). Читаема человеком, но занимает больше места и медленнее обрабатывается.
  • Сериализация с кодировкой — комбинирует бинарную и текстовую формы (например, Base64 для встраивания бинарных данных в JSON).

По области применения

  • Сериализация объектов — для сохранения состояния объектов в файл или передачи по сети (например, в Java RMI, .NET Remoting).
  • Сериализация данных — для обмена данными между системами (например, JSON в REST API, XML в SOAP).
  • Сериализация для кэширования — для быстрого восстановления состояния (например, в Redis, Memcached).
  • Сериализация для распределённых вычислений — для передачи данных между узлами кластера (например, в Apache Spark, Hadoop).

Устройство и характеристики

Механизм работы

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

Ключевые характеристики

  • Совместимость версий — возможность десериализовать данные, созданные старой версией класса, и наоборот. В Java для этого используется поле serialVersionUID.
  • Производительность — скорость сериализации/десериализации и размер результирующих данных. Бинарные форматы обычно быстрее и компактнее текстовых.
  • Безопасность — риск выполнения вредоносного кода при десериализации (например, атаки через pickle в Python или readObject в Java). Для защиты применяются белые списки классов, подписывание данных или использование безопасных форматов (JSON, Protocol Buffers).
  • Кроссплатформенность — возможность обмена данными между системами на разных языках (например, Java и Python через Protocol Buffers).

Примеры в языках программирования

  • Java: интерфейс java.io.Serializable (маркерный интерфейс). Класс должен реализовать его, а все поля (кроме transient и статических) автоматически сериализуются. Пример: class Person implements Serializable { private String name; }.
  • Python: модуль pickle. Любой объект, кроме системных (например, файловых дескрипторов), может быть сериализован. Пример: pickle.dumps(obj).
  • C#: атрибут [Serializable] (пространство имён System). Поля по умолчанию сериализуются, кроме помеченных [NonSerialized]. Пример: [Serializable] public class Person { public string Name; }.
  • C++: нет встроенной сериализации; используются библиотеки (например, Boost.Serialization, Cereal, protobuf).
  • JavaScript/TypeScript: сериализация через JSON.stringify() и JSON.parse(), но только для простых типов (объекты, массивы, строки, числа). Для сложных объектов (с функциями, циклическими ссылками) требуются библиотеки (например, serialize-javascript).

Применение

Сохранение состояния

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

Передача данных по сети

В распределённых системах (веб-сервисы, микросервисы, RPC) сериализация преобразует объекты в байтовые потоки для отправки по HTTP, TCP/IP или другим протоколам. Например, в REST API объекты сериализуются в JSON, а в gRPC — в Protocol Buffers.

Кэширование

В системах кэширования (Redis, Memcached) объекты сериализуются для хранения в оперативной памяти. Это позволяет быстро восстанавливать часто используемые данные (например, результаты запросов к базе данных).

Распределённые вычисления

Фреймворки вроде Apache Spark и Hadoop сериализуют данные для передачи между узлами кластера. Например, в Spark объекты сериализуются с помощью Java Serialization или Kryo для эффективного распределения по исполнителям.

Базы данных

Некоторые базы данных (например, MongoDB, PostgreSQL) поддерживают сериализацию сложных типов (JSON, BSON) для хранения вложенных структур. В объектно-реляционных СУБД (например, Hibernate) объекты сериализуются для хранения в виде BLOB-полей.

Интересные факты

  • В Java сериализация может быть неявной: если класс не реализует Serializable, но содержит ссылку на сериализуемый объект, возникает исключение NotSerializableException.
  • В Python модуль pickle может выполнять произвольный код при десериализации, что делает его небезопасным для данных из ненадёжных источников. Вместо него рекомендуется использовать json или shelve.
  • В C# атрибут [Serializable] устарел в пользу System.Text.Json и System.Runtime.Serialization.DataContractSerializer для современных приложений.
  • Формат Protocol Buffers (protobuf) от Google позволяет определять структуры данных в .proto-файлах и генерировать код для разных языков (Java, C++, Python, Go). Он обеспечивает высокую производительность и обратную совместимость.
  • В 2010-х годах сериализация стала мишенью для атак (например, уязвимость CVE-2015-4852 в Apache Commons Collections, позволявшая удалённое выполнение кода через Java-сериализацию). Это привело к разработке безопасных альтернатив (например, JSON, MessagePack).

Критика

  • Безопасность — встроенная сериализация (особенно в Java и Python) часто содержит уязвимости, позволяющие выполнять произвольный код. Рекомендуется использовать только для доверенных данных или применять форматы без исполняемого кода (JSON, XML).
  • Производительность — бинарная сериализация (например, Java Serialization) может быть медленной и создавать большие объёмы данных. Для высоконагруженных систем предпочтительны Protocol Buffers, Avro или Kryo.
  • Совместимость версий — при изменении класса (добавление/удаление полей) старые сериализованные данные могут стать нечитаемыми. Требуется тщательное управление версиями (например, serialVersionUID в Java).
  • Сложность отладки — бинарные форматы нечитаемы человеком, что затрудняет анализ ошибок. Текстовые форматы (JSON, YAML) проще, но менее эффективны.

Источники

  • Joshua Bloch. Effective Java (3rd edition). Addison-Wesley, 2018. — Глава «Сериализация».
  • Python Software Foundation. pickle — Python object serialization. Документация Python 3.12.
  • Microsoft. Serialization in .NET. Документация Microsoft.
  • Google. Protocol Buffers. Документация protobuf.dev.
  • Apache Spark. Tuning — Data Serialization. Документация Apache Spark.
  • CVE-2015-4852 — Apache Commons Collections Remote Code Execution.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →