序列化、反序列化定义
如果我们需要持久化 Java 对象比如将 Java 对象保存在文件中,或者在网络传输 Java 对象,这些场景都需要用到序列化。
序列化(Serialization)是指将对象转换为字节序列的过程,也可以称之为对象的持久化。在 Java 中,可以通过实现 Serializable 接口来实现对象的序列化。序列化后的字节序列可以保存到文件、数据库或网络中,以便在需要时进行读取和传输。
反序列化(Deserialization)则是将字节序列转换为对象的过程,即恢复出原始的对象。在 Java 中,可以使用 ObjectInputStream 类来进行反序列化操作。反序列化的结果应该与原始对象完全一致,包括所有成员变量的值和对象的状态。
Java 的序列化和反序列化机制是 Java 语言中非常重要的机制之一,它使得 Java 对象可以在不同的 JVM 和系统之间进行传递和共享。但是在实际应用中,需要注意一些序列化和反序列化的问题,如跨语言的兼容性、序列化版本控制、安全性等。
在 C++这种半面向对象的语言中,struct(结构体)定义的是数据结构类型,而 class 对应的是对象类型。
序列化和反序列化应用场景
- 对象在进行网络传输(比如远程方法调用 RPC 的时候)之前需要先被序列化,接收到序列化的对象之后需要再进行反序列化;
- 将对象存储到文件之前需要进行序列化,将对象从文件中读取出来需要进行反序列化;
- 将对象存储到数据库(如 Redis)之前需要用到序列化,将对象从缓存数据库中读取出来需要反序列化;
- 将对象存储到内存之前需要进行序列化,从内存中读取出来之后需要进行反序列化。
序列化和反序列化代码实战
import java.io.*;
public class SerializationDemo {
public static void main(String[] args) {
// 创建一个 Person 对象
Person person = new Person("Alice", 20);
// 对象序列化到文件中
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.txt"))) {
out.writeObject(person);
System.out.println("Person 对象已经序列化到 person.txt 文件中");
} catch (IOException e) {
e.printStackTrace();
}
// 从文件中读取对象并反序列化
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("person.txt"))) {
Person restoredPerson = (Person) in.readObject();
System.out.println("从 person.txt 文件中反序列化出的 Person 对象:" + restoredPerson);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
// 实现 Serializable 接口,使该类可以进行序列化
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 + "}";
}
}
在上述代码中,创建了一个 Person 对象,并将其序列化到 person.ser
文件中。接着从该文件中读取数据,并反序列化出一个新的 Person 对象。最后将这个新的 Person 对象输出到控制台。
需要注意的是,如果要进行序列化和反序列化操作,需要保证被序列化的 Java 对象实现了 java.io.Serializable 接口。此外,还需要使用 ObjectOutputStream 和 ObjectInputStream 来完成序列化和反序列化操作。
为啥不推荐使用 JDK 自带的序列化
不推荐使用 JDK 自带的序列化主要有以下几个原因:
-
可移植性差: JDK 自带的序列化机制生成的序列化数据包含了很多与 Java 版本、类结构等相关的信息,导致序列化数据不够轻量级且不够灵活,在不同的 Java 版本或不同的平台上可能存在兼容性问题。
-
性能问题: JDK 自带的序列化机制在序列化和反序列化过程中会消耗大量的系统资源,且性能较低。特别是对于复杂对象和大数据量的序列化操作,性能表现更加明显。
-
安全性隐患: JDK 自带的序列化机制存在一些安全漏洞,如序列化和反序列化过程中可能会被利用来执行恶意代码(反序列化漏洞),因此不建议在安全性要求较高的场景下使用。
-
不易维护: JDK 自带的序列化机制生成的序列化数据是二进制的,不易读懂和调试,导致对数据的维护和迁移变得困难。
基于以上原因,推荐使用更加灵活、高效、安全的替代方案,如 JSON、XML 等基于文本的序列化方式,或者使用第三方库,如 Google 的 Protocol Buffers、Apache Thrift 等,来代替 JDK 自带的序列化机制。这些替代方案通常具有更好的性能、可移植性和安全性,更适合在实际开发中使用。
常见序列化协议有哪些
-
JSON(JavaScript Object Notation):一种轻量级的数据交换格式,易于阅读和编写,广泛应用于Web应用程序中。JSON支持多种编程语言,并且可以通过各种库实现序列化和反序列化操作。
-
XML(eXtensible Markup Language):一种标记语言,可用于存储和传输数据。XML具有良好的结构性和扩展性,广泛用于数据交换和配置文件中。
-
Protocol Buffers:由Google开发的一种高效的序列化协议,使用二进制格式存储数据,具有较小的数据体积和较高的序列化/反序列化速度。Protocol Buffers定义数据结构和消息格式,生成对应的代码实现序列化和反序列化。
-
Apache Thrift:由Apache开发的跨语言的序列化框架,支持多种编程语言,可以方便地进行跨语言数据交换。Thrift使用IDL(Interface Definition Language)定义数据类型和接口,生成对应的代码用于序列化和反序列化。
-
MessagePack:一种高效的二进制序列化协议,比JSON更小、更快,支持多种编程语言,适合网络传输和存储数据。
-
Avro:一种数据序列化框架,提供动态数据模式和二进制格式,适用于大数据领域的数据交换和存储。
以上是一些常见的序列化协议,每种协议都有其特点和适用场景,选择合适的序列化协议取决于具体的需求和应用场景。
更多消息资讯,请访问昂焱数据。