什么是序列化,一文搞懂!

本文涉及的产品
数据传输服务 DTS,数据迁移 small 3个月
推荐场景:
MySQL数据库上云
数据传输服务 DTS,同步至SelectDB 1个月
数据传输服务 DTS,数据同步 1个月
简介: 序列化介绍

概念说明

 在编程中是一种抽象的概念,就好比“水流”,从一段流向另一端。在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成。程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。

字节流

 它处理单元为1个字节(byte),操作字节和字节数组,存储的是二进制文件,例如存储音频文件、图片、歌曲等

序列化

 将对象转换为字节流的过程,以便在网络传输或持久化存储时使用。序列化可以将对象的状态保存到磁盘或通过网络传输,并在需要时重新创建对象。反序列化则是将字节流转换回对象的过程。

序列化的类型

Java序列化(Java Serialization)

代码实现

import java.io.*;
/**
 * @BelongsProject: demo
 * @BelongsPackage: Java
 * @Author: Wuzilong
 * @Description: Java序列化
 * @CreateTime: 2023-06-28 20:22
 * @Version: 1.0
 */
public class JavaSerializationExample {
    public static void main(String[] args) {
        // 创建对象
        Person person = new Person("Wzill", 18);
        try {
            // 将对象序列化到文件
            FileOutputStream fileOut = new FileOutputStream("person.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(person);
            out.close();
            fileOut.close();
            System.out.println("对象已序列化到文件");
            // 从文件中反序列化对象
            FileInputStream fileIn = new FileInputStream("person.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            Person deserializedPerson = (Person) in.readObject();
            in.close();
            fileIn.close();
            System.out.println("从文件中反序列化对象:" + deserializedPerson);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
import java.io.Serializable;
/**
 * @BelongsProject: demo
 * @BelongsPackage: Java
 * @Author: Wuzilong
 * @Description: person业务类
 * @CreateTime: 2023-06-28 20:22
 * @Version: 1.0
 */
public class Person implements Serializable {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

运行结果

475687a9df00480c857e427e9f5023ee.png

使用场景

 通过实现java.io.Serializable接口,将Java对象转换为字节流。适用于Java环境内的对象序列化和反序列化,可以方便地在Java应用程序之间传递对象。这种方式可以将对象以二进制格式进行序列化和反序列化,但只能在Java环境中使用。

JSON序列化(JSON Serialization)

pom依赖

   

<dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.12.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.12.4</version>
        </dependency>

代码实现

public class JsonSerializationExample {
    public static void main(String[] args) {
        // 创建对象
        Person person = new Person();
        person.setName("wuzilong");
        person.setAge(19);
        try {
            // 将对象序列化为JSON字符串
            ObjectMapper objectMapper = new ObjectMapper();
            String json = objectMapper.writeValueAsString(person);
            System.out.println("JSON字符串:" + json);
            // 将JSON字符串反序列化为对象
            Person deserializedPerson = objectMapper.readValue(json, Person.class);
            System.out.println("从JSON字符串反序列化对象:" + deserializedPerson);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
public class Person {
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Person(){}
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

运行结果

886c189edfaf42c4934527fe369cfd4c.png

使用场景

需要在不同的系统之间进行数据交换和通信,尤其是跨语言和跨平台的通信。

需要在Web应用程序中使用AJAX技术进行前后端数据传输。

需要在移动应用程序中进行数据传输和存储。

XML序列化(XML Serialization)

代码实现

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.io.StringWriter;
/**
 * @BelongsProject: demo
 * @BelongsPackage: Xml
 * @Author: Wuzilong
 * @Description: xml序列化方式
 * @CreateTime: 2023-06-28 20:52
 * @Version: 1.0
 */
public class XmlSerializationExample {
    public static void main(String[] args) {
        // 创建对象
        Person person = new Person();
        person.setName("武梓龙");
        person.setAge(20);
        try {
            // 将对象序列化为XML字符串
            StringWriter writer = new StringWriter();
            JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
            Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(person, writer);
            String xml = writer.toString();
            System.out.println("XML字符串:" + xml);
            // 将XML字符串反序列化为对象
            StringReader reader = new StringReader(xml);
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            Person deserializedPerson = (Person) unmarshaller.unmarshal(reader);
            System.out.println("从XML字符串反序列化对象:" + deserializedPerson);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}
import javax.xml.bind.annotation.XmlRootElement;
/**
 * @BelongsProject: demo
 * @BelongsPackage: Java
 * @Author: Wuzilong
 * @Description: person业务类
 * @CreateTime: 2023-06-28 20:22
 * @Version: 1.0
 */
@XmlRootElement
public class Person {
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Person(){}
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

运行结果

32ad30daa30b449eabaaaa1fc0989bcf.png

使用场景

需要与遵循XML规范的系统进行数据交换和通信。

需要在Web服务中使用SOAP协议进行数据传输。

需要在配置文件中存储和读取结构化数据。

序列化相关注解(Annotation Serialization)

解决不一致问题

1.@JsonProperty:用于指定字段在序列化和反序列化时的名称。可以用于解决字段名和JSON属性名不一致的问题。

public class Person {
    @JsonProperty("full_name")
    private String fullName;
    // getter and setter
}

2.@JsonFormat:用于指定日期和时间字段的序列化和反序列化格式。可以用于解决日期和时间格式不一致的问题。

public class Person {
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate birthDate;
    // getter and setter
}

3.@JsonValue:用于指定字段或方法的返回值应该作为整个对象的JSON表示。可以用于解决对象的整体表示与默认的字段序列化不一致的问题。

public enum Gender {
    MALE("M"),
    FEMALE("F");
    private String code;
    private Gender(String code) {
        this.code = code;
    }
    @JsonValue
    public String getCode() {
        return code;
    }
}

 @JsonValue注解用于指定getCode()方法的返回值应该作为Gender对象的JSON表示,而不是默认的枚举名称。

解决不需要序列化问题

1.@JsonIgnore:用于指定某个字段在序列化和反序列化时被忽略。可以用于解决某些字段不需要被序列化或反序列化的问题。

public class Person {
    private String name;
    @JsonIgnore
    private int age;
    // getter and setter
}

2.@JsonInclude:用于指定在序列化时是否包含某个字段。可以用于解决空字段不需要被序列化的问题。

public class Person {
    @JsonInclude(Include.NON_NULL)
    private String address;
    // getter and setter
}

解决特殊化的问题

1.@JsonAlias:用于指定字段的别名,在反序列化时可以识别多个不同的字段名。可以用于解决字段名变更的问题

public class Person {
    @JsonAlias({"first_name", "given_name"})
    private String firstName;
    // getter and setter
}

2.@JsonTypeInfo:用于指定字段的类型信息,在序列化和反序列化时可以包含类型信息。可以用于解决多态类型的序列化和反序列化问题。

public class Animal {
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
    private String type;
    // getter and setter
}
public class Cat extends Animal {
    private String color;
    // getter and setter
}

3.@JsonSerialize:用于指定自定义的序列化器,将字段的值序列化为指定的格式。可以用于解决字段值需要特殊处理或自定义格式的问题。


public class Actor  {
    @JsonSerialize(using = com.fasterxml.jackson.databind.ser.std.ToStringSerializer.class)
    private Long id;
    // getter and setter
}

序列化案例

问题描述

 我们知道在登录一个平台的时候,登录成功之后后台会把我们的信息返回给前端用来提供一些其他服务的时候使用。比如我们登录成功之后查看一下之前的记录这时候就需要用到我们登录之后返回的数据来查询。查询我们都是使用数据的主键id进行,但是主键id在后端定义为long类型。

ba8c838cb3f146789fcb05b69d6a46b7.png

 这时候当我们将对象进行序列化之后交给前端,前端会把主键id识别为Number类型,但是Number类型只能保留16位。如果主键id长度超过16位就会出现精度丢失的问题,使用丢失精度的主键id自然什么也查询不出来。

问题解决

 这时候我们就可以使用@JsonSerialize注解,在将对象序列化的时候识别为string类型。前端去接收string类型的数据的时候是不会丢失精度的。这样就解决了精度丢失的问题。

26f070f328f54a0e8e029a7a25d13008.png

作用和意义

「数据持久化」:将对象序列化后,可以将其存储到磁盘或数据库中,以便后续读取和恢复对象的状态。

「远程通信」 :在网络传输中,将对象序列化后,可以通过网络传递到远程节点,实现分布式系统之间的通信和数据交换。

「跨平台传递」 :通过序列化,可以将对象转换为通用的格式,以便在不同平台、不同语言之间进行传递和交互。

「对象克隆」 :通过序列化和反序列化,可以实现对象的深度克隆,即创建一个与原始对象完全相同的新对象。

总结提升

 总结起来,序列化和反序列化是在对象和特定格式(如二进制、JSON、XML等)之间进行转换的过程,可以实现数据持久化、数据传输以及跨平台和跨语言通信等功能。不同的序列化方式适用于不同的场景和需求,可以根据具体情况选择合适的方式进行序列化和反序列化操作。


相关实践学习
自建数据库迁移到云数据库
本场景将引导您将网站的自建数据库平滑迁移至云数据库RDS。通过使用RDS,您可以获得稳定、可靠和安全的企业级数据库服务,可以更加专注于发展核心业务,无需过多担心数据库的管理和维护。
Sqoop 企业级大数据迁移方案实战
Sqoop是一个用于在Hadoop和关系数据库服务器之间传输数据的工具。它用于从关系数据库(如MySQL,Oracle)导入数据到Hadoop HDFS,并从Hadoop文件系统导出到关系数据库。 本课程主要讲解了Sqoop的设计思想及原理、部署安装及配置、详细具体的使用方法技巧与实操案例、企业级任务管理等。结合日常工作实践,培养解决实际问题的能力。本课程由黑马程序员提供。
相关文章
|
存储 网络协议 C语言
一文带你秒懂 字节序(byte order),比特序(bit order),位域(bit field)
一文带你秒懂 字节序(byte order),比特序(bit order),位域(bit field)
1490 0
|
JSON 人工智能 自然语言处理
Prompt进阶系列4:LangGPT(构建高性能Prompt实践指南)--结构化Prompt
Prompt进阶系列4:LangGPT(构建高性能Prompt实践指南)--结构化Prompt
|
SQL 关系型数据库 MySQL
【Mysql实战】问题分析利器之binlog
在【Mysql-InnoDB 系列】事务提交过程及系列文章中,对mysql(InnoDB引擎)的redolog、undolog、binlog及事务的提交过程有了一些介绍,本篇将尝试去实践binlog在日常操作中的查看、分析方式,以及可能遇到的问题和解决方法。
886 0
|
开发框架 前端开发 Linux
开源项目推荐:C++ Web/Http Server/Rest开发框架(请重点关注Oat++和搜狗workflow)
开源项目推荐:C++ Web/Http Server/Rest开发框架(请重点关注Oat++和搜狗workflow)
4937 0
|
7月前
|
人工智能 Linux iOS开发
7.9K star!免费解锁Cursor Pro功能,这个开源神器太强了!
"无需付费即可畅享AI编程神器Cursor的Pro功能,支持Windows/macOS/Linux全平台!"
2211 4
|
自然语言处理 JavaScript 程序员
UTF-8 GBK UTF8 GB2312 之间的区别和关系
【8月更文挑战第24天】UTF-8(Unicode Transformation Format-8bit)是一种多字节编码方案,用于解决国际化字符编码问题,英文使用一个字节编码,中文使用三个字节。它涵盖了全球所有国家的字符,具备良好的通用性,可在支持UTF-8的浏览器上显示。尽管可包含字节顺序标记(BOM),但通常不使用。GBK是在GB2312基础上扩展的标准,使用双字节编码,包括所有中文字符,但通用性较弱。UTF-8和GBK之间需通过Unicode转换。对于含有大量英文字符的网站或论坛,使用UTF-8编码可节省存储空间。
451 5
|
Java 程序员 调度
Java基础18-一文搞懂Java多线程使用方式、实现原理以及常见面试题(一)
Java基础18-一文搞懂Java多线程使用方式、实现原理以及常见面试题(一)
199 0
Java基础18-一文搞懂Java多线程使用方式、实现原理以及常见面试题(一)
|
JavaScript 前端开发
模块化(Modularization)是一种软件工程实践,旨在将大型、复杂的系统分割成一系列松散耦合、功能独立且具有明确定义接口的模块。
模块化简化复杂软件,通过划分独立模块提升代码可读性、维护性、复用性和扩展性。JavaScript模块化有多种方式:CommonJS(Node.js,`require()`/`module.exports`),AMD(RequireJS,异步加载,`define()`/`require()`),以及ES6 Modules(官方标准,`import`/`export`)。早期还有闭包和IIFE等非正式方法。现代工具如Webpack和Rollup处理兼容性问题,使模块化代码能在各种环境中运行。
377 0
|
自然语言处理 图形学
【Unity实战】实现强大通用易扩展的对话系统(附项目源码)
【Unity实战】实现强大通用易扩展的对话系统(附项目源码)(2023/12/26补充更新)
1332 0
|
存储 XML 消息中间件
一文彻底搞懂序列化和反序列化
一文彻底搞懂序列化和反序列化