objectinputstream反序列化需满足四要素:类实现serializable并声明serialversionuid;所有非transient字段及其父类均须可序列化;必须用fileinputstream套objectinputstream且不可跳过header;须捕获ioexception、classnotfoundexception、invalidclassexception。

用 ObjectInputStream 恢复对象,核心不是“读文件”那么简单,而是确保整个反序列化链路严丝合缝:类要可序列化、文件必须是 ObjectOutputStream 写出的、流要正确打开、类型要安全转换。
类必须实现 Serializable 并声明 serialVersionUID
被恢复的类必须显式实现 java.io.Serializable 接口,并强烈建议声明固定值的 serialVersionUID:
- 不加
serialVersionUID时,JVM 根据类结构自动生成;一旦字段增删、类型变更或在不同 JDK 版本下编译,生成值就不同,直接抛InvalidClassException - 推荐写法:
private static final long serialVersionUID = 1L;(或用 IDE 生成带哈希的稳定值) - 所有非 transient 字段类型也必须可序列化;父类若含实例字段,也得实现
Serializable,否则报NotSerializableException - 不想保存的字段(如密码、连接池、线程等)用
transient修饰,反序列化后为默认值(null、0、false)
必须用 FileInputStream 套 ObjectInputStream,且不能跳过 header
ObjectInputStream 只认 ObjectOutputStream 写出的二进制格式,开头有固定 4 字节魔数 AC ED 00 05。任何偏差都会导致 StreamCorruptedException:
- 构造方式必须是:
new ObjectInputStream(new FileInputStream("xxx.ser")) - 不能提前读取文件流(比如先用
FileInputStream.read()),否则 position 偏移,header 读错 - 避免套
BufferedInputStream—— 缓冲区可能多读后续字节,破坏对象图结构 - 文件必须由
ObjectOutputStream.writeObject()写入,且写完调用close()或flush()
用 try-with-resources 安全读取并处理三类关键异常
readObject() 返回 Object,需强制转型,但失败前必须兜住常见错误:
- 用
try(FileInputStream fis = new FileInputStream("data.ser"); ObjectInputStream ois = new ObjectInputStream(fis))自动关闭资源,防止句柄泄漏 - 必须捕获并区分:
IOException(文件不存在、损坏、权限问题)、ClassNotFoundException(类不在 classpath,如 jar 包缺失或包名改了)、InvalidClassException(serialVersionUID 不匹配或类结构不兼容) - 转型前建议加
instanceof判断或判空,避免ClassCastException或NullPointerException掩盖真实问题
反序列化不调用构造方法,只靠反射填充字段
ObjectInputStream 底层不走 new 或构造器,而是通过 JVM 反射直接分配内存并写入字段值:
- 所有字段(除
static和transient)按写入时的顺序和类型,一对一映射填充 - 要求运行时类的全限定名、字段名、类型、声明顺序与序列化时完全一致;大小写差异、字段删除、类型升级(如
int→Integer)都会失败 - 父类字段能否恢复,取决于父类是否实现
Serializable;未实现则其字段不参与序列化,反序列化后为默认值 - 若需定制恢复逻辑(如重置 static 状态、重建 transient 资源),可在类中定义
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException方法
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











