单元测试中适合用序列化克隆,因其通过Serializable机制实现真正深拷贝,确保所有嵌套对象完全独立、不共享引用,满足隔离性与可重复性要求;且无需修改原类结构、绕过访问限制、避免手动clone遗漏。

在单元测试中用序列化实现对象克隆,本质是利用 Java 的 Serializable 机制完成深拷贝,确保测试用例之间互不干扰。这种方式绕过构造方法和字段访问限制,适合快速生成独立副本。
为什么单元测试里适合用序列化克隆
单元测试强调隔离性与可重复性。若直接赋值或浅克隆,修改克隆对象的引用字段(如 List、嵌套 POJO)会意外影响原始测试数据。序列化克隆能保证: - 所有层级对象(包括嵌套引用)都被完整复制 - 不依赖各字段的 getter/setter 或 public 访问权限 - 避免手动重写 clone 方法带来的遗漏风险 - 原始对象无需修改结构(只要实现 Serializable 即可)
基础实现:内存中序列化 + 反序列化
不写磁盘,全程在字节数组中完成,高效且无副作用:
- 被克隆类及其所有成员变量类型(含内部类、集合元素类型)必须实现 Serializable
- 推荐为每个类显式声明
private static final long serialVersionUID = 1L;,避免反序列化失败 - 使用
ByteArrayOutputStream和ByteArrayInputStream在内存操作 - 捕获并处理
IOException和ClassNotFoundException
示例工具方法:
public static <t> T serializeClone(T obj) throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.close();
<pre class="brush:php;toolbar:false;">ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
@SuppressWarnings("unchecked")
T cloned = (T) ois.readObject();
ois.close();
return cloned;
}
在 JUnit 测试中直接调用
以 Student 类为例(含 Address 引用):
- 测试前准备一个干净的源对象:
Student original = new Student(1, "Alice", new Address("Beijing")); - 克隆:
Student cloned = serializeClone(original); - 修改克隆体:
cloned.getAddress().setProvince("Shanghai"); - 断言验证独立性:
assertNotEquals(original.getAddress().getProvince(), cloned.getAddress().getProvince());
这样就能确认 address 字段也被真正复制,不是共享引用。
注意边界情况
序列化克隆不是万能的,需留意:
- transient 字段不会被复制,如果测试依赖这些字段,需额外初始化或改用其他方式
- 静态字段不属于对象状态,自然不会参与序列化,不影响测试逻辑
- 包含不可序列化类型(如 Thread、Socket、某些第三方类)会抛异常,此时应排除该字段或换用 Kryo/JSON 方案
- 若类中有自定义
writeObject/readObject,需确保逻辑正确,否则克隆结果可能不符合预期
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











