cglib beancopier性能最强,耗时约25–40ms/10万次,基于字节码生成、复用高效;其次为手动get/set(10–15ms),spring beanutils(300–500ms)和jackson序列化(1200–2000ms)依次下降。

直接用基准测试对比四种主流对象拷贝方式的效率,关键不是堆砌工具,而是控制变量、聚焦真实开销。以下方法在 JDK 17+、单线程、Warmup 充分(如 JMH)条件下验证有效,结果具备参考性。
选对测试对象和场景
使用结构清晰、含基本类型+1~2层引用类型的 POJO(如 CurrencyDailyBo:含 int、double、Date、String、Integer),避免空对象或极端嵌套。每轮测试执行 10 万次拷贝,取中位数耗时,排除 JIT 预热干扰。
- 确保所有方式操作同一原始实例,避免因对象状态差异引入偏差
- 禁用 GC 日志干扰,固定堆内存(如
-Xms512m -Xmx512m) - 引用类型字段(如
Date)需确认是否参与深拷贝逻辑——否则比的是“半拷贝”
四种方式实测性能排序(由快到慢)
以 10 万次拷贝为单位,典型耗时范围(单位:毫秒):
- get/set 手动赋值:≈ 10–15 ms —— 直接字段访问,无反射、无序列化开销,最快
- Cglib BeanCopier:≈ 25–40 ms —— 字节码生成一次后复用,运行期高效,兼顾开发效率
- Spring BeanUtils.copyProperties:≈ 300–500 ms —— 基于反射+缓存,首次调用略慢,后续稳定
- JSON 序列化(Jackson):≈ 1200–2000 ms —— 涉及字符串编解码、类型推断、临时对象创建,最重
注意:原生 clone() 若仅浅拷贝,可能快至 5 ms 内,但不满足“深拷贝”需求;若强行递归重写 clone 实现深拷贝,性能接近手动 get/set,但代码维护成本陡增。
避开常见跑分陷阱
很多“低效结论”其实源于测试设计失当:
- 未预热就测
BeanUtils:前几次反射解析慢,拉高均值,应丢弃前 1000 次 - 用
JSON.stringify测 Java 对象:JS 方式不适用于 JVM 环境,属跨语言误比 - 让
SerializationUtils.clone()处理未实现Serializable的类:直接抛异常,测的不是性能而是容错 - 混用不同 JVM 参数(如开启/关闭 TieredStopAtLevel):影响 JIT 行为,导致结果不可比
实用建议:按需选型,不唯快论
性能只是维度之一,落地还要看可维护性与约束条件:
- 高频拷贝且对象稳定 → 用
get/set或BeanCopier - 快速交付、对象常变、允许依赖 →
Spring BeanUtils更省心 - 已有 JSON 流水线、对象纯数据、不涉二进制字段 →
Jackson可复用生态 - 强一致性要求、嵌套深、含自定义类型 → 手动拷贝构造函数仍是鲁棒性首选










