前言
Java对象的序列化和反序列化的问题,在分布式系统中常常容易被忽视。曾经在工作中踩过坑,最近又看到不少同事在这个问题上踩坑,故想写一篇博客来示警戒,同时也望能帮助到为此问题感到困惑的诸君
1. 什么是Java对象的序列化和反序列化
- 序列化: 将Java对象转化成字节流。 可作为对象持久化的一种实现方式,但更多体现在将对象的属性和方法转换成字节流便于远程通信传输
- 反序列化: 将字节流转换成Java对象。
2. JDK中相关的API
- 输出流对象:java.io.ObjectOutputStream。它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化成字节流,把得到的字节流写到一个目标输出流中(如:文件输出流等)。
- 输入流:java.io.ObjectInputStream。它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回。
3. 关于Serializable接口
- Java对象能被序列化的前提是实现了Serializable接口或者其子接口Externalizable
- 序列化场景多被应用于分布式场景的RPC调用,所有传输Java对象须强制实现Serializable来保证反序列化的成功(这一点将在后续铺开叙述)
4. demo及分析
Student.java
public class Student implements Serializable {
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;
}
}
SerializableTest.java(包含两个方法:一个序列化方法,一个反序列化方法)
public class SerializableTest {
/**
* Student序列化
*/
public static void serialize() {
Student student = new Student();
student.setAge(15);
student.setName("张三");
ObjectOutputStream ots = null;
try {
//指定java对象Person序列化后的字节流输出的目标流
ots = new ObjectOutputStream(new FileOutputStream("D:/studentStream.txt"));
//将Person序列化成的字节流写入到目标输出流(此处为文件输出流)中
ots.writeObject(student);
System.out.println("序列化成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (ots != null) {
ots.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Student序列化字节的反序列化操作
*/
public static void deSerialize() {
ObjectInputStream inputStream = null;
try {
//指定序列化字节流的来源
inputStream = new ObjectInputStream(new FileInputStream("D:/studentStream.txt"));
//将字节流反序列化成Object对象(在这里进行了强转)
Student student = (Student) inputStream.readObject();
System.out.println("执行反序列化过程成功:" + student.getName() + "-" + student.getAge() + "岁");
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
//1. 先执行序列化方法
serialize();
Thread.sleep(1000);
//2. 后执行反序列化方法
deSerialize();
}
}
demo分析
SerializableTest.java的main方法中:
- 先执行序列化方法,执行后可在指定目录:"D:/studentStream.txt"中看到被序列化后的Student字节流
- 为了让反序列化执行更加直观,第二步中直接将反序列化后的Student对象信息打印出来
总结
- Java对象是否能被序列化,其前提是实现 java.io.Serializable 接口
- 序列化的出现:为Java对象的持久化提供了一种解决方案,同时又对远程通信过程,如:分布式系统中PRC建立的连接提供了支持