如何实现java序列化:三种主流方案实操
如何实现java序列化分为原生JDK序列化、JSON文本序列化、Protobuf二进制序列化三类;原生方案实现Serializable标识接口并配置serialVersionUID,用ObjectOutputStream完成字节流转换,仅适用于Java内部JVM通信;JSON序列化借助Jackson、Gson把对象转为字符串,适合REST接口跨语言交互;Protobuf先编写proto文件生成实体代码,序列化体积更小、速度更快,适合RPC高并发场景;所有方案都不能序列化Thread、Socket这类系统资源对象,若成员变量不可序列化,必须加上transient修饰符跳过该字段,否则程序抛出异常。
java原生序列化实现步骤
你先给实体类实现java.io.Serializable标记接口,该接口没有抽象方法,仅作为序列化识别标识;接着手动定义privatestaticfinallongserialVersionUID=1L,避免JDK自动生成版本号,防止类结构小幅修改后反序列化失败。
你使用ObjectOutputStream把对象写入文件或网络输出流,完成序列化;再用ObjectInputStream读取字节流,还原成Java对象,完成反序列化。
静态字段与被transient修饰的字段不会被序列化,这是JDK内置规则。
JSON序列化实现步骤
你在项目中引入Jackson或Gson依赖,不需要给实体类实现任何序列化接口,直接调用工具类方法把对象转为JSON字符串,反序列化时再把字符串转回实体对象。
JSON序列化会丢失完整类型信息,泛型集合反序列化时必须明确指定目标类型,否则会出现类型转换错误。
Protobuf序列化实现步骤
你先编写.proto协议文件,定义字段名称与编号,使用protoc工具自动生成Java实体类;调用生成类自带的toByteArray()方法完成序列化,调用parseFrom(byte[])方法实现反序列化。
该方案必须提前维护协议文件,不能直接复用现有Java实体类,开发工作量会有所增加。
| 序列化方式 | 跨语言能力 | 数据体积 | 开发成本 | 适用场景 |
|---|---|---|---|---|
| JDK原生序列化 | 仅支持Java | 偏大 | 低 | 单机缓存、同JVM之间数据传输 |
| JSON序列化 | 多语言通用 | 中等 | 低 | HTTP接口、前后端数据交互 |
| Protobuf序列化 | 多语言通用 | 更小 | 偏高 | RPC远程调用、高并发网络传输 |
边界限制与异常规避
只要实体中包含Thread、InputStream、Socket等系统资源类成员,无论采用哪种方案,都无法正常序列化,必须把这类成员标记为transient,或者在序列化前手动清空资源对象。
原生序列化还有反序列化安全风险,《EffectiveJavaThirdEdition》中给出建议,尽量减少在对外接口中直接使用JDK原生序列化机制。
子类实现序列化时,如果父类没有实现Serializable接口,父类必须提供无参构造方法,不然反序列化会触发InvalidClassException异常。
