应使用集合封装一次性序列化/反序列化多个对象;若必须逐个追加,需重写writestreamheader跳过重复流头并仅捕获eofexception判定结束,同时显式声明serialversionuid并校验类兼容性。

Java 中反序列化多个对象不能简单套用单次 readObject() 加循环的方式,因为 ObjectInputStream 在文件末尾会抛出 EOFException(不是普通结束信号),直接捕获并忽略容易掩盖真实异常,也难以区分“读完”和“损坏/截断”。安全读取多个对象的关键是**统一容器封装 + 显式边界控制**。
推荐做法:把多个对象装进集合再整体序列化
这是最稳妥、最常用、也最符合 Java 序列化设计意图的方式。不逐个追加,而是先收集,再一次性写入。
- 序列化时,把所有对象放入
ArrayList、LinkedList或HashSet等可序列化集合中,然后只调用一次writeObject(collection) - 反序列化时,只调用一次
readObject(),强转为对应集合类型,再遍历使用 - 集合本身实现了
Serializable,且能完整保留元素类型、数量和顺序,无歧义、无异常风险
如果必须逐个写入(如日志追加场景),需手动管理流头
默认的 ObjectOutputStream 每次新建都会写入一个“流头(stream header)”,而 ObjectInputStream 只认第一个头;后续追加的对象会导致反序列化失败(StreamCorruptedException)。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 解决方案:继承
ObjectOutputStream,重写writeStreamHeader(),在非首次写入时跳过头部 - 反序列化端仍用标准
ObjectInputStream,但需配合try-catch(EOFException)判定结束——仅用于明确可控的追加场景 - 注意:
EOFException是唯一可接受的终止信号;IOException或ClassNotFoundException必须中断并报错,不可静默吞掉
反序列化前务必校验类定义与版本兼容性
即使读取逻辑正确,若反序列化时类结构已变更(字段删改、未声明 serialVersionUID),仍会抛 InvalidClassException,导致数据不可用。
- 每个可序列化类都应显式声明
private static final long serialVersionUID = xxxL; - 修改类时谨慎调整
serialVersionUID:兼容性变更(如加transient字段)可保持值不变;破坏性变更(如删非 transient 字段)需更新值并提供自定义readObject兜底 - 生产环境建议搭配白名单机制(如通过
ObjectInputStream.resolveClass限制可加载类),防止反序列化攻击
小结:安全优先选集合封装,追加需控流头,版本与校验不可少
没有“万能循环读取”的捷径。真正安全的做法是放弃逐个追加的思路,转向结构化存储;若业务强依赖追加,就必须自己接管流头逻辑,并严格区分正常结束与异常中断。同时,serialVersionUID 和类加载控制是保障长期可读性的基础防线。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










