readUnshared()的核心作用是禁止对象图中重复引用,强制单次调用内对象仅出现一次且不参与全局引用表共享;它不创建深拷贝,但可配合writeUnshared()实现逻辑隔离实例。

readUnshared() 的核心作用不是“确保全新副本”,而是禁止对象图中出现重复引用——它强制每个被反序列化的对象在本次调用中只能出现一次,且不参与全局反序列化引用表(reference table)的共享机制。
它不创建深拷贝,也不做克隆
很多人误以为 readUnshared() 会自动深拷贝对象。实际上:
- 它仍按正常流程反序列化字段,包括对其他可序列化对象的引用;
- 但一旦某个对象(比如子对象 A)在本次 readUnshared() 调用中已被反序列化过,再次遇到相同序列化句柄时,会直接抛出 ObjectStreamException(通常是 InvalidObjectException 或 StreamCorruptedException);
- 它绕过 ObjectInputStream 内部的「已反序列化对象缓存表」,所以即使同一个对象实例在流中被多次写入(如通过 writeUnshared()),也不会复用引用。
适用场景:防止意外的引用共享
典型用于需要强隔离性的场景,例如:
- 反序列化不受信数据时,避免攻击者构造循环引用或共享引用触发逻辑异常;
- 实现“单次有效凭证”类对象(如一次性 Token),确保每次读取都得到逻辑上独立的实例;
- 测试中验证对象是否真的被重建,而非复用了旧引用(配合自定义 readObject() 验证 this 是否为新实例)。
如何真正获得“全新副本”?需配合其他手段
若目标是得到一个与原对象内容相同但内存完全独立(尤其是嵌套对象也全新)的副本,readUnshared() 单独不够,还需:
- 所有嵌套类型都必须实现 Serializable,否则反序列化中断;
- 在 writeObject() / readObject() 中主动切断共享:例如对集合字段手动 new + copy,或对可变内部状态做防御性复制;
- 更可靠的方式是结合 SerializationUtils.clone()(Apache Commons Lang)或使用 JSON 二次序列化(如 Jackson + readValueAs()),它们天然不共享引用;
- 注意:final 字段、enum、Class 等 JVM 特殊类型始终是共享的,无法通过反序列化“复制”。
一个小验证示例
假设有类 Container 持有同一个 Data 实例两次:
- 用 writeObject() 写入 → 反序列化后两个字段指向同一对象(引用共享);
- 改用 writeUnshared() 写入两次 → readUnshared() 第二次会失败,除非流中确实是两个独立序列化块;
- 若分别用 writeUnshared() 写两次不同对象,再用两次 readUnshared() 读取 → 得到两个相互无关的新实例(无跨调用引用,也无同次调用内共享)。


















