写 Java 时难免遇到序列化,但很多人提到它就打哈欠。直到面试官盯着你问:“Serializable 为啥要 serialVersionUID?transient 有啥用?”——这时候你才觉得,这东西真不是摆设。去网络查了半天,发现大家都讲得挺公式的,我这里想从真正在项目和面试里踩过的坑来说说。
想象一下,你有一个对象,某一天要把它“拿出来存档”,可能是写文件、可能是发给另外一台服务器。序列化(serialize)在 Java 里,就是把对象变成一串二进制,之后能再从这串二进制“复活”出对象。反过来就是反序列化(deserialize)了。
这听起来挺直白,但坑在细节。
我拿一个简单的类举例,先看看怎么把它写进文件、再读回来:
import java.io.*;
// 这是个能被序列化的类
class Account implements Serializable {
private static final long serialVersionUID = 42L; // 面试常问
private String username;
private transient String secret; // 不想序列化的字段
public Account(String username, String secret) {
this.username = username;
this.secret = secret;
}
public String toString() {
return username + " | secret=" + secret;
}
}
public class SerializeDemo {
public static void main(String[] args) throws Exception {
Account acct = new Account("alice", "123456");
// 写出去
try (ObjectOutputStream out =
new ObjectOutputStream(new FileOutputStream("acct.bin"))) {
out.writeObject(acct);
}
// 读回来
try (ObjectInputStream in =
new ObjectInputStream(new FileInputStream("acct.bin"))) {
Account recovered = (Account) in.readObject();
System.out.println("Loaded: " + recovered);
}
}
}
运行完你可能会发现,打印出来的 secret 是 null。原因是我们把它 transient了——意思是“别管它,不参与序列化过程”。这在面试里是个常考点:敏感信息(比如密码)要别序列化,否则写到磁盘谁都能读出。
有些面试官会专门问:
“为什么要写
serialVersionUID?不写会怎样?”
答案不难抓住:
序列化机制内部会根据类结构生成一个默认版本号。如果你序列化以后改了类结构(比如新增字段),再去反序列化旧数据,很可能抛出 InvalidClassException。主动写了 serialVersionUID,就是自己把版本号钉死,这让旧数据还能顺利反序列化(当然要你自己判断字段语义是否兼容)。
还有一些更细碎但面试常问的实战:
▪ 字段有非 Serializable 类型怎么办?
如果你的类里有字段引用了一个不支持序列化的对象,会抛 NotSerializableException。
解决办法也不复杂:
- 要么把该字段标记成
transient, - 要么让那个字段本身也实现
Serializable。
这在面试里出现得挺高频,特别是你写了一个包含第三方库对象的类去序列化的时候。
▪ Externalizable?为什么有人提它
有些面试会往深走一步,问你有没有比 Serializable 更灵活的方式。
答案是 Externalizable:它需要你自己写出序列化和反序列化逻辑,更费事,但能更精细控制保存内容。对大对象、多版本协议的系统有用。
▪ 序列化不只是写文件
尽管示例里是写文件,但其实场景更广:
- 分布式缓存(把对象放进 Redis 之类的),
- JVM 之间对象传输,
- Web session 在集群间复制(很多 servlet 容器会自动序列化 session 对象)。
面试问到这些场景时,你能具体说出来比只讲概念要有含金量。
写到这儿你可能会想,“这不就是把对象扔到字节流然后再捡回来吗?”对,就是这样,但为什么有那么多人说这东西容易错、不安全、被现代微服务架构嫌弃?因为 Java 自带的序列化格式是 JVM 专有的,不容易在不同语言/服务间共享,而且一不小心的反序列化确实有安全隐患——这也是大公司喜欢用 JSON、Protobuf 这些替代方案的原因。
如果你在面试里说:“我知道怎么写 Serializable 并且了解 transient、serialVersionUID,还能简单讲讲 Externalizable 和安全性问题”,往往比背一堆定义更能打动对方。因为面试不只是问你怎么写代码,更想知道你对“为什么这么做”和“实际风险”的理解。