← Назад к вопросам

Какие знаешь способы сериализации объекта?

1.8 Middle🔥 111 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Способы сериализации объектов в Java

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

1. Java Serialization (Встроенная сериализация)

Использует интерфейс Serializable и встроенные потоки.

Базовый пример

import java.io.*;

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;
    private transient String password;  // ✅ Не сериализуется
    
    public User(String name, int age, String password) {
        this.name = name;
        this.age = age;
        this.password = password;
    }
    
    // getters/setters
}

// Сериализация
User user = new User("John", 30, "secret123");

try (ObjectOutputStream oos = new ObjectOutputStream(
        new FileOutputStream("user.ser"))) {
    oos.writeObject(user);  // ✅ Сохраняем в файл
}

// Десериализация
try (ObjectInputStream ois = new ObjectInputStream(
        new FileInputStream("user.ser"))) {
    User loadedUser = (User) ois.readObject();  // ✅ Загружаем из файла
    System.out.println(loadedUser.getName());
}

Кастомная сериализация

public class CustomSerializable implements Serializable {
    private String data;
    private transient int cachedValue;  // Не сохраняем
    
    // ✅ Кастомная логика при сохранении
    private void writeObject(ObjectOutputStream oos) 
            throws IOException {
        oos.defaultWriteObject();  // Сохраняем значения по умолчанию
        oos.writeInt(cachedValue);  // Сохраняем кэш отдельно
    }
    
    // ✅ Кастомная логика при загрузке
    private void readObject(ObjectInputStream ois) 
            throws IOException, ClassNotFoundException {
        ois.defaultReadObject();
        cachedValue = ois.readInt();  // Восстанавливаем кэш
    }
}

Проблемы встроенной сериализации

// ❌ Взаимозависимость версий
// Если изменить класс, старые .ser файлы не загрузятся

// ❌ Медленно: много оверхеда
// ❌ Небезопасно: возможно создание объектов без конструктора
// ❌ Не переносимо: только Java → Java

2. JSON (Jackson)

Самый популярный способ для REST API и обмена данными.

import com.fasterxml.jackson.databind.ObjectMapper;

public class User {
    private String name;
    private int age;
    private String email;
    
    // getters/setters
}

// Сериализация в JSON
ObjectMapper mapper = new ObjectMapper();
User user = new User("John", 30, "john@example.com");

String json = mapper.writeValueAsString(user);
System.out.println(json);
// Вывод: {"name":"John","age":30,"email":"john@example.com"}

// Десериализация из JSON
User loadedUser = mapper.readValue(json, User.class);

Кастомная сериализация в JSON

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;

public class Order {
    @JsonProperty("order_id")  // Меняем имя в JSON
    private String id;
    
    @JsonIgnore  // Не сохраняем это поле
    private String internalNotes;
    
    @JsonFormat(pattern = "yyyy-MM-ddTHH:mm:ss")
    private LocalDateTime createdAt;
}

Запись в файл

ObjectMapper mapper = new ObjectMapper();
User user = new User("Jane", 25, "jane@example.com");

// Запись в файл
mapper.writeValue(new File("user.json"), user);

// Чтение из файла
User loaded = mapper.readValue(new File("user.json"), User.class);

3. Protocol Buffers (Protobuf)

Мощный формат для обмена данными между микросервисами.

// user.proto файл
syntax = "proto3";
package com.example;

message User {
    string name = 1;
    int32 age = 2;
    string email = 3;
}

// Скомпилированный Java класс
import com.example.UserProto;

// Сериализация
UserProto.User user = UserProto.User.newBuilder()
    .setName("John")
    .setAge(30)
    .setEmail("john@example.com")
    .build();

byte[] bytes = user.toByteArray();  // ✅ Компактный бинарный формат

// Десериализация
UserProto.User loaded = UserProto.User.parseFrom(bytes);
System.out.println(loaded.getName());

Преимущества Protobuf

// ✅ Очень компактно (меньше байтов)
// ✅ Быстро (оптимизировано)
// ✅ Типобезопасно
// ✅ Версионируемо
// ❌ Требует .proto файлы
// ❌ Менее читаемо (бинарный формат)

4. XML

Для обмена между разными системами, часто в enterprise.

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

@XmlRootElement
public class User {
    @XmlElement
    private String name;
    
    @XmlElement
    private int age;
    
    @XmlElement
    private String email;
}

// Сериализация в XML
User user = new User("John", 30, "john@example.com");
JAXBContext context = JAXBContext.newInstance(User.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(user, new File("user.xml"));

// Десериализация из XML
Unmarshaller unmarshaller = context.createUnmarshaller();
User loaded = (User) unmarshaller.unmarshal(new File("user.xml"));

Результат XML

<?xml version="1.0" encoding="UTF-8"?>
<user>
    <name>John</name>
    <age>30</age>
    <email>john@example.com</email>
</user>

5. YAML

Читаемый формат для конфигурации и обмена.

import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.databind.ObjectMapper;

public class User {
    public String name;
    public int age;
    public String email;
}

// Сериализация в YAML
ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory());
User user = new User();
user.name = "John";
user.age = 30;
user.email = "john@example.com";

String yaml = yamlMapper.writeValueAsString(user);
System.out.println(yaml);
// Вывод:
// name: John
// age: 30
// email: john@example.com

// Десериализация из YAML
User loaded = yamlMapper.readValue(yaml, User.class);

6. CSV

Для табличных данных и экспорта.

import com.opencsv.CSVWriter;
import com.opencsv.CSVReader;

public class CSVExample {
    static class User {
        String name;
        int age;
        String email;
    }
    
    public static void serializeToCSV(List<User> users) throws IOException {
        try (CSVWriter writer = new CSVWriter(new FileWriter("users.csv"))) {
            // Заголовок
            writer.writeNext(new String[]{"Name", "Age", "Email"});
            
            // Данные
            for (User user : users) {
                writer.writeNext(new String[]{
                    user.name,
                    String.valueOf(user.age),
                    user.email
                });
            }
        }
    }
    
    public static List<User> deserializeFromCSV() throws IOException {
        List<User> users = new ArrayList<>();
        try (CSVReader reader = new CSVReader(new FileReader("users.csv"))) {
            String[] headers = reader.readNext();  // Пропускаем заголовок
            String[] values;
            
            while ((values = reader.readNext()) != null) {
                User user = new User();
                user.name = values[0];
                user.age = Integer.parseInt(values[1]);
                user.email = values[2];
                users.add(user);
            }
        }
        return users;
    }
}

7. MessagePack

Бинарный формат, быстрее JSON, но более читаемо чем Protobuf.

import org.msgpack.jackson.dataformat.MessagePackFactory;
import com.fasterxml.jackson.databind.ObjectMapper;

public class User {
    public String name;
    public int age;
    public String email;
}

// Сериализация
ObjectMapper msgpackMapper = new ObjectMapper(new MessagePackFactory());
User user = new User();
user.name = "John";
user.age = 30;
user.email = "john@example.com";

byte[] packed = msgpackMapper.writeValueAsBytes(user);
System.out.println("Size: " + packed.length + " bytes");  // Очень компактно

// Десериализация
User loaded = msgpackMapper.readValue(packed, User.class);

8. Avro

Для больших данных (Big Data, Kafka, Hadoop).

import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.io.Encoder;
import org.apache.avro.io.EncoderFactory;

public class AvroExample {
    static String schema = "{" +
        "\"type\": \"record\"," +
        "\"name\": \"User\"," +
        "\"fields\": [" +
            "{\"name\": \"name\", \"type\": \"string\"}," +
            "{\"name\": \"age\", \"type\": \"int\"}," +
            "{\"name\": \"email\", \"type\": \"string\"}" +
        "]" +
    "}";
    
    public static void main(String[] args) throws Exception {
        Schema avroSchema = new Schema.Parser().parse(schema);
        
        // Создание записи
        GenericRecord record = new GenericData.Record(avroSchema);
        record.put("name", "John");
        record.put("age", 30);
        record.put("email", "john@example.com");
        
        // Сериализация
        DatumWriter<GenericRecord> datumWriter = new GenericDatumWriter<>(avroSchema);
        Encoder encoder = EncoderFactory.get()
            .binaryEncoder(new ByteArrayOutputStream(), null);
        datumWriter.write(record, encoder);
    }
}

Сравнение методов

МетодРазмерСкоростьЧитаемостьПримеры
Java SerializationБольшойМедленноНетLegacy, RMI
JSONСреднийСреднеВысокаяREST API, Web
ProtobufМаленькийБыстроНизкаяgRPC, микросервисы
XMLБольшойМедленноСредняяEnterprise, SOAP
YAMLСреднийМедленноВысокаяКонфиги
CSVСреднийМедленноВысокаяExcel, отчёты
MessagePackМаленькийБыстроНизкаяPerformance
AvroМаленькийОчень быстроНизкаяBig Data

Рекомендации

// ✅ REST API, Web → JSON (Jackson)
// ✅ Микросервисы высоконагруженные → Protobuf или Avro
// ✅ Конфигурация → YAML
// ✅ Табличные данные → CSV
// ✅ Наследие Java → Java Serialization (осторожно!)
// ❌ Никогда → Java Serialization для untrusted источников (RCE risk)

// ✅ Выбирай JSON для начала — универсально

Заключение

Выбор способа сериализации зависит от:

  1. Читаемость → JSON, YAML
  2. Производительность → Protobuf, Avro, MessagePack
  3. Совместимость → JSON (универсален)
  4. Табличные данные → CSV
  5. Наследие системы → XML, Java Serialization (осторожно!)

Для большинства современных приложений JSON — оптимальный выбор по соотношению читаемости, скорости и универсальности.