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

本文涉及的产品
数据传输服务 DTS,数据同步 small 3个月
推荐场景:
数据库上云
数据传输服务 DTS,数据迁移 small 3个月
推荐场景:
MySQL数据库上云
数据传输服务 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等)之间进行转换的过程,可以实现数据持久化、数据传输以及跨平台和跨语言通信等功能。不同的序列化方式适用于不同的场景和需求,可以根据具体情况选择合适的方式进行序列化和反序列化操作。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
Sqoop 企业级大数据迁移方案实战
Sqoop是一个用于在Hadoop和关系数据库服务器之间传输数据的工具。它用于从关系数据库(如MySQL,Oracle)导入数据到Hadoop HDFS,并从Hadoop文件系统导出到关系数据库。 本课程主要讲解了Sqoop的设计思想及原理、部署安装及配置、详细具体的使用方法技巧与实操案例、企业级任务管理等。结合日常工作实践,培养解决实际问题的能力。本课程由黑马程序员提供。
相关文章
|
24天前
|
存储 缓存 NoSQL
一篇搞懂!Java对象序列化与反序列化的底层逻辑
本文介绍了Java中的序列化与反序列化,包括基本概念、应用场景、实现方式及注意事项。序列化是将对象转换为字节流,便于存储和传输;反序列化则是将字节流还原为对象。文中详细讲解了实现序列化的步骤,以及常见的反序列化失败原因和最佳实践。通过实例和代码示例,帮助读者更好地理解和应用这一重要技术。
24 0
|
6月前
|
存储 XML JSON
日常小知识点之序列化结构(protobuf使用及简单原理)
日常小知识点之序列化结构(protobuf使用及简单原理)
178 0
|
6月前
|
XML 存储 JSON
【序列化】的一些基础知识
【序列化】的一些基础知识
|
XML 存储 C#
C#三十一 序列化与反序列化
C#三十一 序列化与反序列化
48 0
|
数据库 数据格式 Python
聊一聊序列化和反序列化
聊一聊序列化和反序列化
107 1
|
存储 XML 消息中间件
一文彻底搞懂序列化和反序列化
一文彻底搞懂序列化和反序列化
|
JSON 前端开发 关系型数据库
高频面试题-DRF-序列化-反序列化
Django-drf框架最大的亮点莫过于Serializer序列化器这个操作了, 它极大的简化了程序员在模型类和JSON数据格式之间转换的代码,节省了大量的时间和遍历。
高频面试题-DRF-序列化-反序列化
|
存储 JSON 缓存
面试官问我为什么要序列化,我竟然答不上来
什么是序列化?为什么要序列化?什么时候序列化?
121 0
|
存储 XML JSON
序列化和反序列化的底层实现原理是什么?
序列化和反序列化的底层实现原理是什么?
173 0
|
安全 Java 编译器
54. Java序列化三连问,是什么?为什么需要?如何实现?
54. Java序列化三连问,是什么?为什么需要?如何实现?
138 0
54. Java序列化三连问,是什么?为什么需要?如何实现?