概念说明
流
在编程中是一种抽象的概念,就好比“水流”,从一段流向另一端。在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成。程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。
字节流
它处理单元为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 + "]"; } }
运行结果
使用场景
通过实现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 + "]"; } }
运行结果
使用场景
需要在不同的系统之间进行数据交换和通信,尤其是跨语言和跨平台的通信。
需要在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 + "]"; } }
运行结果
使用场景
需要与遵循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类型。
这时候当我们将对象进行序列化之后交给前端,前端会把主键id识别为Number类型,但是Number类型只能保留16位。如果主键id长度超过16位就会出现精度丢失的问题,使用丢失精度的主键id自然什么也查询不出来。
问题解决
这时候我们就可以使用@JsonSerialize注解,在将对象序列化的时候识别为string类型。前端去接收string类型的数据的时候是不会丢失精度的。这样就解决了精度丢失的问题。
作用和意义
「数据持久化」:将对象序列化后,可以将其存储到磁盘或数据库中,以便后续读取和恢复对象的状态。
「远程通信」 :在网络传输中,将对象序列化后,可以通过网络传递到远程节点,实现分布式系统之间的通信和数据交换。
「跨平台传递」 :通过序列化,可以将对象转换为通用的格式,以便在不同平台、不同语言之间进行传递和交互。
「对象克隆」 :通过序列化和反序列化,可以实现对象的深度克隆,即创建一个与原始对象完全相同的新对象。
总结提升
总结起来,序列化和反序列化是在对象和特定格式(如二进制、JSON、XML等)之间进行转换的过程,可以实现数据持久化、数据传输以及跨平台和跨语言通信等功能。不同的序列化方式适用于不同的场景和需求,可以根据具体情况选择合适的方式进行序列化和反序列化操作。