为了了解序列化我们先从序列化的过程入手,从而类比来理解其概念。
序列化的过程分为以下几个阶段:
-
序列化:对象通过序列化器转换为字节流;
-
存储/传输:字节流被写入文件、数据库或通过网络发送;
-
反序列化:字节流被反序列化器读取并转换回对象。
为了更形象更简单地理解这几个概念,阿伟为大家类比了生活中的一个实例:
场景:在美好的未来中的某一天,你正在制作一个三明治,这个三明治包含了多种食材,比如面包、火腿、生菜、奶酪和番茄。现在,你的朋友在另一个城市,他也想制作一个一模一样的三明治,但是他没有你这里的食材。
①序列化的过程就像是你把三明治的制作信息写在一张纸上,这张纸包含了所有制作三明治所需的信息:
-
2片面包
-
3片火腿
-
2片生菜
-
1片奶酪
-
2片番茄
这张纸就是序列化后的数据,它包含了创建一个三明治所需的所有信息,但是它是以一种可以轻松传输和存储的格式存在的。
②存储的过程就像是你把这张纸放在一个信封里,然后把它保存在抽屉里。这样,即使过了一段时间,你也能根据这张纸重新制作三明治。
③传输的过程就像是你把这张纸放在另一个信封里,通过邮件发送给你的朋友。你的朋友收到信封后,可以根据里面的信息在当地购买相应的食材。
④反序列化的过程就像是你的朋友收到信封,根据里面的信息在当地购买食材,然后按照纸上的指示制作三明治。最终,他成功地制作出了一个和你这里一模一样的三明治。
在这个例子中,三明治就是你的对象,那张纸就是序列化后的数据,保存和传输的过程就是序列化数据的存储和传输,而你朋友根据纸上的信息制作三明治的过程就是反序列化。
理解了概念之后,就该思考那为什么要进行序列化呢?序列化又有什么好处呢?
1.数据持久化
-
保存状态:通过序列化,我们可以将程序的状态保存下来,以便在程序关闭后再次启动时恢复到之前的状态。
-
跨平台存储:序列化的数据可以存储在多种类型的存储介质上,如硬盘、光盘、USB驱动器等。
2.网络通信
-
远程调用:在分布式系统中,序列化允许对象在网络上传输,使得远程计算机可以接收这些对象并执行相应的操作。
-
数据交换:不同的系统或服务之间可以通过序列化来交换数据,如通过HTTP请求发送JSON或XML格式的数据。
3.内存管理
-
优化内存使用:在某些情况下,序列化可以用于优化内存使用,例如,通过序列化对象到磁盘来减少内存中活跃对象的数量。若一直放在内存当中,会增大内存的消耗。
了解了以上内容,就该去实践一下啦,今天举例一下“数据持久化”的使用场景:
import java.io.*;
public class DataPersistenceExample {
public static void main(String[] args) {
try {
// 创建对象
MyObject obj = new MyObject("awei", 18);
// 序列化对象到文件
FileOutputStream fileOut = new FileOutputStream("myObject.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(obj);
out.close();
fileOut.close();
// 从文件反序列化对象
FileInputStream fileIn = new FileInputStream("myObject.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
MyObject deserializedObj = (MyObject) in.readObject();
in.close();
fileIn.close();
// 输出反序列化对象的信息
System.out.println("Name: " + deserializedObj.name);
System.out.println("Age: " + deserializedObj.age);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
static class MyObject implements Serializable {
private static final long serialVersionUID = 1L;
String name;
int age;
MyObject(String name, int age) {
this.name = name;
this.age = age;
}
}
}
上述代码解析:
-
FileOutputStream fileOut = new FileOutputStream("myObject.ser");
:创建一个FileOutputStream
对象,用于将数据写入名为"myObject.ser"的文件。 -
ObjectOutputStream out = new ObjectOutputStream(fileOut);
:创建一个ObjectOutputStream
对象,它包装了FileOutputStream
,用于将对象序列化到文件。 -
out.writeObject(obj);
:将MyObject
对象写入文件。 -
out.close();
:关闭ObjectOutputStream
。 -
fileOut.close();
:关闭FileOutputStream
。 -
FileInputStream fileIn = new FileInputStream("myObject.ser");
:创建一个FileInputStream
对象,用于从名为"myObject.ser"的文件中读取数据。 -
ObjectInputStream in = new ObjectInputStream(fileIn);
:创建一个ObjectInputStream
对象,它包装了FileInputStream
,用于从文件中反序列化对象。 -
MyObject deserializedObj = (MyObject) in.readObject();
:从文件中读取对象,并将其转换为MyObject
类型。 -
in.close();
:关闭ObjectInputStream
。 -
fileIn.close();
:关闭FileInputStream
。 -
System.out.println("Name: " + deserializedObj.name);
:打印反序列化对象的name
属性。 -
System.out.println("Age: " + deserializedObj.age);
:打印反序列化对象的age
属性。 -
private static final long serialVersionUID = 1L;
:定义一个serialVersionUID
字段,它是序列化对象的唯一标识符。
序列化时,数据传递的流程是:
1.从内存中的对象(obj)到ObjectOutputStream(out)。
2.然后通过ObjectOutputStream写入到FileOutputStream(fileOut)。
3.最后,FileOutputStream将数据写入到文件系统上的文件("myObject.ser")。
序列化是将对象的状态信息转换为可以存储或传输的形式的过程,而反序列化则是相反的过程。在这个例子中,MyObject
对象被序列化到一个名为"myObject.ser"的文件中,然后从该文件中反序列化回来,并打印出对象的属性。
结束~