什么是序列化和反序列化
序列化(Serialization)和反序列化(Deserialization)是指在计算机科学中将对象转换为字节流的过程以及将字节流重新转换为对象的过程。
序列化是将对象的状态转换为字节流的过程,以便存储到磁盘、通过网络传输或在内存中进行持久化。通过序列化,对象可以被保存或传输,并且可以在需要时重新还原为原始对象。
反序列化是将字节流转换为对象的过程。通过反序列化,我们可以从字节流中恢复出之前序列化的对象,并重新构建该对象的状态。这使得我们可以在不同的计算机、进程或网络中传递对象,并在需要时重新还原。
序列化和反序列化经常用于分布式系统、持久化存储、缓存、进程间通信等场景。它们使得对象可以以紧凑的二进制形式进行存储和传输,方便在不同环境中使用和共享对象。
实现方式(推荐前两种)
1.Java 原生的 Serializable 接口实现实体类序列化
你可以使用 Java 的 `ObjectOutputStream` 和 `ObjectInputStream` 类来进行实体类的序列化和反序列化。以下是一个封装了实体类序列化和反序列化方法的示例代码:
import java.io.*;
public class SerializationUtil {
// 将对象序列化为字节数组
public static byte[] serialize(Object object) {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {
objectOutputStream.writeObject(object);
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
// 将字节数组反序列化为对象
public static Object deserialize(byte[] data) {
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)) {
return objectInputStream.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
}
在这个示例中,`SerializationUtil` 类封装了两个静态方法。`serialize` 方法接收一个对象作为参数,将该对象序列化为一个字节数组并返回。`deserialize` 方法接收一个字节数组作为参数,将该字节数组反序列化为一个对象并返回。
要使用这些方法,只需调用对应方法并传入相应的参数即可。例如:
Person person = new Person("张三", 20);
// 对象序列化
byte[] data = SerializationUtil.serialize(person);
// 对象反序列化
Person deserializedPerson = (Person) SerializationUtil.deserialize(data);
上述代码中,我们创建了一个 `Person` 对象,并将其序列化为字节数组。然后,我们再将这个字节数组反序列化为一个新的 `Person` 对象 `deserializedPerson`。
需要注意的是,被序列化的对象必须实现 `Serializable` 接口,并且所有字段都应该是可序列化的。同时,要确保序列化和反序列化使用相同的类加载器和类结构,否则可能会导致反序列化失败。此外,Java 原生的序列化方式并不适用于大规模数据和高性能场景,因此在实际应用中,推荐使用其他高效的序列化框架,如 Avro、Protobuf ,Jackson 等。
2.使用 Jackson 库实现序列化和反序列化:
首先,确保你已经在项目中引入了 Jackson 库的依赖。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.4</version>
</dependency>
然后,你可以使用 Jackson 的 ObjectMapper
类来实现序列化和反序列化。以下是示例代码:
import com.fasterxml.jackson.databind.ObjectMapper;
public class SerializationUtil {
private static ObjectMapper objectMapper = new ObjectMapper();
// 将对象序列化为 JSON 字符串
public static String serialize(Object object) throws IOException {
return objectMapper.writeValueAsString(object);
}
// 将 JSON 字符串反序列化为对象
public static <T> T deserialize(String json, Class<T> valueType) throws IOException {
return objectMapper.readValue(json, valueType);
}
}
在上述代码中,我们使用 Jackson 提供的 ObjectMapper
类来进行序列化和反序列化操作。serialize
方法将一个对象序列化为 JSON 字符串,并返回该字符串。deserialize
方法接收一个 JSON 字符串和目标对象的类型,将 JSON 字符串反序列化为对应的对象并返回。
使用实例:
Person person = new Person("张三", 20);
// 对象序列化
String json = SerializationUtil.serialize(person);
// 对象反序列化
Person deserializedPerson = SerializationUtil.deserialize(json, Person.class);
3.使用 Google 的 Protobuf 库实现序列化和反序列化:
首先,确保你已经在项目中引入了 Protobuf 库的依赖。
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.17.3</version>
</dependency>
定义 .proto
文件来描述你的数据结构:
syntax = "proto3";
message Person {
string name = 1;
int32 age = 2;
}
然后,使用 Protobuf 提供的代码生成工具(protoc
)根据 .proto
文件生成相应的 Java 类。在生成的 Java 类中,Person
类提供了 toByteArray()
方法用于序列化,以及 parseFrom(byte[] data)
方法用于反序列化。
public class SerializationUtil {
// 将对象序列化为字节数组
public static byte[] serialize(Person person) {
return person.toByteArray();
}
// 将字节数组反序列化为对象
public static Person deserialize(byte[] data) throws InvalidProtocolBufferException {
return Person.parseFrom(data);
}
}
使用实例:
Person person = Person.newBuilder()
.setName("张三")
.setAge(20)
.build();
// 对象序列化
byte[] data = SerializationUtil.serialize(person);
// 对象反序列化
Person deserializedPerson = SerializationUtil.deserialize(data);
4.用avro实现实体类的序列化和反序列化
定义 Avro Schema(模式): 首先,你需要定义一个 Avro Schema 来描述你的数据结构。Schema 可以使用 Avro 的 JSON 或者编程接口来定义。
例如,假设你有一个 Person 类,你可以创建一个名为 person.avsc
的文件,其中包含以下内容:
{
"type": "record",
"name": "Person",
"fields": [
{"name": "name", "type": "string"},
{"name": "age", "type": "int"}
]
}
- 通过 Avro 工具生成 Java 类:然后,你需要使用 Avro 工具将 Avro Schema 文件转换成相应的 Java 类。你可以使用命令行工具 avro-tools.jar 来完成这一步。
java -jar avro-tools.jar compile schema person.avsc ./output/
这将会生成名为 Person.java
的 Java 类文件,位于 ./output/
目录下。
2.使用生成的 Java 类进行序列化和反序列化:接下来,你可以使用生成的 Java 类来进行实体类的序列化和反序列化。
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.io.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class SerializationUtil {
private static Schema schema; // Avro Schema
static {
try {
schema = new Schema.Parser().parse(SerializationUtil.class.getResourceAsStream("/output/person.avsc"));
} catch (IOException e) {
e.printStackTrace();
}
}
// 将对象序列化为字节数组
public static byte[] serialize(Person person) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
DatumWriter<GenericData.Record> datumWriter = new GenericDatumWriter<>(schema);
Encoder encoder = EncoderFactory.get().binaryEncoder(outputStream, null);
GenericData.Record avroRecord = new GenericData.Record(schema);
avroRecord.put("name", person.getName());
avroRecord.put("age", person.getAge());
datumWriter.write(avroRecord, encoder);
encoder.flush();
outputStream.close();
return outputStream.toByteArray();
}
// 将字节数组反序列化为对象
public static Person deserialize(byte[] data) throws IOException {
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
DatumReader<GenericData.Record> datumReader = new GenericDatumReader<>(schema);
Decoder decoder = DecoderFactory.get().binaryDecoder(inputStream, null);
GenericData.Record avroRecord = datumReader.read(null, decoder);
inputStream.close();
return new Person(
avroRecord.get("name").toString(),
(int) avroRecord.get("age")
);
}
}
在上述代码中,我们使用 Apache Avro 的相关类来实现序列化和反序列化操作。首先,我们加载 Avro Schema 文件(person.avsc
),然后根据 Schema 创建 GenericData.Record
对象来表示数据,并使用 GenericDatumWriter
和 GenericDatumReader
进行序列化和反序列化。
使用实例:
Person person = new Person("张三", 20);
// 对象序列化
byte[] data = SerializationUtil.serialize(person);
// 对象反序列化
Person deserializedPerson = SerializationUtil.deserialize(data);
这样,你就可以使用 Avro 实现实体类的序列化和反序列化了。记得将 Avro Schema 文件和生成的 Java 类文件添加到你的项目中。