Java 如何序列化对象
你肯定有过这样的经历:手机里存了好久的照片,换个手机就能直接导过去,不用重新下载;电脑里的游戏存档,重装系统后还能接着用——这些“把东西存起来、再拿出来用”的操作,背后其实藏着一个很实用的技术:对象序列化。今天咱们就用大白话聊聊,Java里是怎么给对象“打包存档”的。
什么是Java对象序列化?
你可以把Java对象想象成你桌上的一个小摆件:它有自己的样子(属性,比如摆件的颜色、大小),还有自己的“行为逻辑”(方法,比如摆件能转个方向)。平时它放在桌上(程序运行时的内存里),断电就没了。而序列化,就是把这个“摆件”拆成一个个能存起来的小零件,打包成一个文件或者一串数据,相当于把摆件“压缩存档”;等以后需要用的时候,再把这个压缩包解包,变回原来的摆件——这就是反序列化。

举个生活化的例子:你给朋友寄了个组装好的乐高模型,直接寄容易碎,也不方便,于是你把它拆成小零件,装在盒子里,朋友收到后再拼回去。这个“拆成零件打包”的过程,就像序列化;“拼回去”就是反序列化。Java的对象序列化,干的就是乐高这种事。
怎么让Java对象能被序列化?
不是所有Java对象都能直接打包的,就像不是所有东西都能随便装盒子寄——得有个“允许打包”的标识。Java里有个专门的“许可标签”,叫Serializable接口,它是个空接口,里面啥代码都没有,就像一个“我同意被打包”的签名。
比如你要做一个“学生”对象,有姓名、年龄这两个属性,那你只需要让这个类实现Serializable接口就行:
`java
import java.io.Serializable;
// 学生类,同意被序列化
public class Student implements Serializable {
// 序列化版本号,就像盒子上的快递单号,避免拆包出错
private static final long serialVersionUID = 1L;
// 学生的姓名
private String name;
// 学生的年龄
private int age;
// 构造方法,创建学生对象时用
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
`
这里的serialVersionUID就像是快递的“唯一单号”,要是以后你修改了学生类(比如加了个“学号”属性),这个单号不变的话,老的序列化文件还能正常拆包,不会出错。
序列化和反序列化怎么操作?
光有许可还不够,得有工具来打包和解包。Java提供了ObjectOutputStream来做“打包工具”,ObjectInputStream来做“解包工具”。
比如把一个学生对象存成文件(打包):
`java
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class SerializeDemo {
public static void main(String[] args) {
Student student = new Student("小明", 12);
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student.dat"))) {
// 把学生对象写入文件,完成序列化
oos.writeObject(student);
} catch (Exception e) {
e.printStackTrace();
}
}
}
`
等以后需要用这个学生对象,就用ObjectInputStream读文件解包(反序列化):
`java
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class DeserializeDemo {
public static void main(String[] args) {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student.dat"))) {
// 从文件中读取对象,完成反序列化
Student student = (Student) ois.readObject();
System.out.println("姓名:" + student.name + ",年龄:" + student.age);
} catch (Exception e) {
e.printStackTrace();
}
}
}
`
运行这段代码,你会看到控制台输出“姓名:小明,年龄:12”——这说明打包的对象成功解出来了。
哪些情况需要注意?
不是所有对象的属性都需要打包的,比如你有个学生的“临时成绩”,这个数据是程序运行时算出来的,关机就没了,没必要存。这时候可以用transient关键字标记这个属性,告诉序列化工具“这个属性别打包”。比如在学生类里加个临时成绩:
`java
private transient int tempScore;
`
序列化的时候,这个tempScore的值就会被忽略,解包后它会变成默认值0,不会保留原来的数值。
另外,要是对象里还有其他对象属性,那这个属性对应的类也得实现Serializable接口,不然打包会出错——就像你打包的乐高里,有个小玩偶,那这个玩偶也得能拆成零件,不然没法一起打包。
现在你再看那些“换手机导数据”“游戏存档”的操作,是不是明白背后的小原理了?Java的对象序列化,就是这么简单的“打包和解包”,只要记得给对象签个“许可标签”,再用工具操作,就能轻松把对象存起来、拿出来用。