Java跨网络序列化需实现Serializable并显式声明serialVersionUID,用ObjectOutputStream/ObjectInputStream包装Socket流传输,注意类路径、字节序、协议头及反序列化安全风险。

Java 中通过序列化传输跨网络的对象数据,本质是把对象转成字节流,再借助网络 I/O 发送到远端,对方再反序列化还原。这个过程看似简单,但涉及协议、安全、兼容性和性能多个关键点。
必须实现 Serializable 并管理 serialVersionUID
要让一个类能被跨网络传输,它及其所有非 transient 成员类都必须实现 Serializable 接口。这不是功能接口,而是一个标记——告诉 JVM “这个类允许被序列化”。
强烈建议显式声明 serialVersionUID,比如:
private static final long serialVersionUID = 1L;否则 JVM 会自动生成,一旦类结构变化(如增删字段、改访问修饰符),生成的 UID 就不同,远端反序列化时直接抛 InvalidClassException,导致通信中断。
立即学习“Java免费学习笔记(深入)”;
用 ObjectOutputStream 写出,ObjectInputStream 读入
在网络场景中,不直接操作文件流,而是把 ObjectOutputStream 包装在 Socket 的输出流上,把 ObjectInputStream 包装在输入流上。
- 发送端:创建 Socket → 获取 OutputStream → 套上 ObjectOutputStream → 调用 writeObject() 发送对象
- 接收端:监听 Socket → 获取 InputStream → 套上 ObjectInputStream → 调用 readObject() 获取对象
注意:readObject() 返回的是 Object,需强制转型为原始类型,且该类必须在接收方 classpath 中存在,否则抛 ClassNotFoundException。
注意网络协议和字节序一致性
Java 原生序列化是二进制格式,依赖 JVM 实现细节,对跨语言支持差(比如 Python 或 Go 无法直接解析)。它也默认不保证网络字节序统一,如果收发两端 JVM 版本差异大(如 Java 8 ↔ Java 17),某些内部字段可能解析异常。
更稳妥的做法是:在 TCP 层之上定义简单协议头(如 4 字节长度前缀),避免粘包;或改用通用序列化方案(如 JSON、Protobuf)替代原生序列化,尤其在异构系统间通信时。
警惕反序列化安全风险
远程反序列化是高危操作。攻击者若能控制字节流,可构造恶意 payload 触发任意代码执行(如利用 Commons Collections 链)。生产环境严禁直接反序列化不可信来源的数据。
- 禁用危险类:通过 ObjectInputStream 子类重写 resolveClass(),白名单校验类名
- 优先使用 JSON 或 Avro 等不执行逻辑的序列化格式
- 如必须用原生序列化,确保通信链路可信(如内网 + TLS 加密 + 认证)


















