Java序列化详解:什么情况下必须用它?

最近在公司写代码的时候,碰上了一个问题:怎么把一个对象"存起来",下次还能原样读出来?

比如用户登录后,他的信息(用户名、ID、权限等)存在一个User对象里。如果服务器重启了,这个对象就没了,用户又得重新登录------这体验太差了。

后来同事告诉我,用"序列化"就能解决这个问题。一开始我也听得一头雾水,什么序列化、反序列化,听着像科幻片里的术语。但用多了才发现,其实它挺简单的,而且特别实用。

今天我就用自己的话,讲讲什么是Java序列化,什么时候会用到它,还有反序列化是干啥的。

一、什么是Java序列化?

简单的说:把一个Java对象变成一串字节,存到文件里或者通过网络发出去,这个过程就叫序列化。

就像你拍张照片,可以把一个活生生的人"变成"一个数字文件,传给朋友看。序列化就是把内存里的对象,"拍成"一串可以存储或传输的字节流。

举个例子:

假设你有一个用户类:

java 复制代码
public class User implements Serializable {
    private String name;
    private int age;
    private String email;

    // 构造方法、get/set省略
}

注意这个Serializable接口。它是Java自带的,你只要让类实现它,这个类的对象就可以被序列化了。

然后你可以这样把它"存起来":

java 复制代码
User user = new User("张三", 28, "zhangsan@email.com");

// 把对象写入文件
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.dat"));
oos.writeObject(user);
oos.close();

这时候你会发现项目目录下多了一个user.dat文件。虽然你看不懂里面的内容(因为是字节),但它已经把"张三"这个对象完整地保存下来了。

二、什么时候需要序列化?

我总结了几个最常见的场景,都是我在项目里实际遇到的:

1. 把数据保存到本地文件

比如你写了个小工具,用户设置了一些偏好(主题颜色、字体大小等),你想下次打开时还能记住这些设置。

就可以把这些设置封装成一个对象,序列化存到本地。下次启动时反序列化读回来,用户的设置就"复活"了。

2. 网络传输对象

比如你做了一个客户端-服务器程序,客户端要传一个订单对象给服务器。

你不能直接把对象"扔"过去,得先序列化成字节流,通过网络发过去,服务器再反序列化还原成对象。

做聊天软件时,每条消息都是一个Message对象,就是靠序列化发过去的。

3. 缓存对象(比如Redis)

虽然Redis常用JSON存数据,但有时候你不想折腾转JSON,可以直接把对象序列化后存进Redis。

比如用户登录后,把User对象序列化存到Redis,设置个过期时间。之后每次请求直接从Redis读,不用查数据库,速度快。

4. 深拷贝对象

你可能知道对象赋值是"引用",改一个另一个也跟着变。

序列化+反序列化,可以快速实现一个"深拷贝":

java 复制代码
// 把对象序列化再反序列化,相当于克隆了一个全新的对象
User user2 = (User) deserialize(serialize(user1));

这样 user2user1 完全独立,改哪个都不影响另一个。


三、反序列化是啥?

反序列化就是序列化的"逆过程":把那一串字节重新变回Java对象。

继续上面的例子,你想读回"张三"的信息:

java 复制代码
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.dat"));
User user = (User) ois.readObject();
ois.close();

System.out.println(user.getName()); // 输出:张三

看,对象又回来了!就像你从照片里"复活"了那个人。

四、要注意的坑

虽然序列化很方便,但也有些坑我们很容易踩:

1. 类必须实现 Serializable

不是所有类都能序列化。你的类必须 implements Serializable,否则会报错。

java 复制代码
public class User implements Serializable { ... }

2. serialVersionUID 最好手动指定

Java会自动给序列化类生成一个版本号。如果你改了类(比如加了个字段),再反序列化旧数据,可能会失败。

解决办法:手动加一个 serialVersionUID

java 复制代码
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    // ...
}

这样即使类有小改动,也能尽量兼容旧数据。

3. 敏感字段要标记transient

比如密码、银行卡号这些不想被序列化的字段,加上transient

java 复制代码
private transient String password;

这样序列化时会自动跳过这个字段,更安全。


五、小结:序列化就像"对象的快照"

序列化就是"对象 → 字节",反序列化就是"字节 → 对象"。 只要你想把对象存起来或发出去,就得请这对兄弟帮忙。

什么时候用?记住这几个关键词就行:

  • 保存对象状态
  • 跨网络传对象
  • 做深拷贝
  • 缓存复杂对象

下次你遇到类似需求,不妨试试序列化。几行代码,就能让对象"活"得更久。

本文首发于微信公众号「刘大华的开发笔记」我是大华,专注分享前后端开发的实战笔记。 关注我,少走弯路,一起进步!

相关推荐
David爱编程4 分钟前
Java 守护线程 vs 用户线程:一文彻底讲透区别与应用
java·后端
即将进化成人机30 分钟前
Maven架构的依赖管理和项目构建
java·架构·maven
qianmoq1 小时前
第03章:无限流:generate()和iterate()的神奇用法
java
whitepure1 小时前
万字详解JVM
java·jvm·后端
我崽不熬夜1 小时前
Java的条件语句与循环语句:如何高效编写你的程序逻辑?
java·后端·java ee
我崽不熬夜1 小时前
Java中的String、StringBuilder、StringBuffer:究竟该选哪个?
java·后端·java ee
草明2 小时前
docker stats 增加一列容器名称的显示
java·开发语言·docker
期待のcode2 小时前
Maven的概念与Maven项目的创建
java·maven
我崽不熬夜2 小时前
Java中的基本数据类型和包装类:你了解它们的区别吗?
java·后端·java ee
我是廖志伟3 小时前
【jar包启动,每天生成一个日志文件】
java·jar