拷贝简单对象的四种方法及性能分析
前言
本文转自美女程序媛,她的博客原文地址: https://blog.csdn.net/duagh7/article/details/80857463
实际项目中,我们常常需要对对象进行拷贝,此文将列出四种常见的对象拷贝方式,并针对它们分别做出实验进行性能分析。
此次实验用于拷贝的简单对象如下:
class CurrencyDailyBo implements Serializable { private static final long serialVersionUID = 1L; private int id; private Date day; private double amountMoney; private int businessNum; private int balanceNum; private Integer type; private String createTime; private String modifyTime ; public int getId() { return id; } public void setId(int id) { this.id = id; } public Date getDay() { return day; } public void setDay(Date day) { this.day = day; } public double getAmountMoney() { return amountMoney; } public void setAmountMoney(double amountMoney) { this.amountMoney = amountMoney; } public int getBusinessNum() { return businessNum; } public void setBusinessNum(int businessNum) { this.businessNum = businessNum; } public int getBalanceNum() { return balanceNum; } public void setBalanceNum(int balanceNum) { this.balanceNum = balanceNum; } public String getCreateTime() { return createTime; } public void setCreateTime(String createTime) { this.createTime = createTime; } public Integer getType() { return type; } public void setType(Integer type) { this.type = type; } public String getModifyTime() { return modifyTime; } public void setModifyTime(String modifyTime) { this.modifyTime = modifyTime; } @Override public String toString() { return JSON.toJSONString(this); } }
方法一、get / set方法
最原始拷贝对象的方法,new一个新对象,然后进行get,set方法拷贝属性,代码如下:
@Test public void getset() { CurrencyDailyBo currencyDailyBo = new CurrencyDailyBo(); currencyDailyBo.setAmountMoney(111); currencyDailyBo.setBalanceNum(1); currencyDailyBo.setBusinessNum(2); currencyDailyBo.setCreateTime("today"); currencyDailyBo.setModifyTime("today"); currencyDailyBo.setDay(new Date()); currencyDailyBo.setId(1111111); currencyDailyBo.setType(1); long start = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { CurrencyDailyBo copyBo = new CurrencyDailyBo(); copyBo.setType(currencyDailyBo.getType()); copyBo.setId(currencyDailyBo.getId()); copyBo.setDay(currencyDailyBo.getDay()); copyBo.setAmountMoney(currencyDailyBo.getAmountMoney()); copyBo.setBalanceNum(currencyDailyBo.getBalanceNum()); copyBo.setBusinessNum(currencyDailyBo.getBusinessNum()); copyBo.setCreateTime(currencyDailyBo.getCreateTime()); copyBo.setModifyTime(currencyDailyBo.getModifyTime()); } long cost = System.currentTimeMillis() - start; System.out.println("get,set方法拷贝10万个简单对象,耗时====" + cost); }
运行结果:
get,set方法拷贝10万个简单对象,耗时====15
方法二、beanutils工具类拷贝
第二种方法我们使用apache提供的工具类(spring也提供了类似的工具类)beanutils.copyProperties来进行拷贝,其底层实现原理为反射,代码如下:
@Test public void beanutilsForCopy() throws InvocationTargetException, IllegalAccessException { CurrencyDailyBo currencyDailyBo = new CurrencyDailyBo(); currencyDailyBo.setAmountMoney(111); currencyDailyBo.setBalanceNum(1); currencyDailyBo.setBusinessNum(2); currencyDailyBo.setCreateTime("today"); currencyDailyBo.setModifyTime("today"); currencyDailyBo.setDay(new Date()); currencyDailyBo.setId(1111111); currencyDailyBo.setType(1); long start = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { CurrencyDailyBo copyBo = new CurrencyDailyBo(); BeanUtils.copyProperties(copyBo, currencyDailyBo); } long cost = System.currentTimeMillis() - start; System.out.println("beanutils工具类拷贝10万个简单对象,耗时====" + cost); }
运行结果:
beanutils工具类拷贝10万个简单对象,耗时====3495
方法三、通过json字符串转入转出
第三种方法我们通过fastjson将对象转入json字符串,再使用parseObject转出为对象,代码如下:
@Test public void jsonForCopy() { CurrencyDailyBo currencyDailyBo = new CurrencyDailyBo(); currencyDailyBo.setAmountMoney(111); currencyDailyBo.setBalanceNum(1); currencyDailyBo.setBusinessNum(2); currencyDailyBo.setCreateTime("today"); currencyDailyBo.setModifyTime("today"); currencyDailyBo.setDay(new Date()); currencyDailyBo.setId(1111111); currencyDailyBo.setType(1); long start = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { String json = JSON.toJSONString(currencyDailyBo); CurrencyDailyBo copyBo = JSON.parseObject(json, CurrencyDailyBo.class); } long cost = System.currentTimeMillis() - start; System.out.println("jsonString拷贝10万个简单对象,耗时====" + cost); }
运行结果:
jsonString拷贝10万个简单对象,耗时====374
此方法还可用于原被拷贝对象为map集合的情况。
方法四、重写clone方法
这种方法在实际项目中较少使用,它是通过实现cloneable接口及重写clone方法来拷贝对象,但它的效率是最高的,有条件的情况下可以使用该方法。对于复杂对象(嵌套、链表等)来说,必须对其子对象也实现clone方法,否则拷贝结果会丢失子对象的属性数据,代码如下:
@Test public void cloneForCopy() { CurrencyDailyBo currencyDailyBo = new CurrencyDailyBo(); currencyDailyBo.setAmountMoney(111); currencyDailyBo.setBalanceNum(1); currencyDailyBo.setBusinessNum(2); currencyDailyBo.setCreateTime("today"); currencyDailyBo.setModifyTime("today"); currencyDailyBo.setDay(new Date()); currencyDailyBo.setId(1111111); currencyDailyBo.setType(1); long start = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { Object copyBo = currencyDailyBo.clone(); } long cost = System.currentTimeMillis() - start; System.out.println("clone方法拷贝10万个简单对象,耗时====" + cost); }
重写对象:
class CurrencyDailyBo implements Serializable ,Cloneable{ private static final long serialVersionUID = 1L; private int id; private Date day; private double amountMoney; private int businessNum; private int balanceNum; private Integer type; private String createTime; private String modifyTime; public int getId() { return id; } public void setId(int id) { this.id = id; } public Date getDay() { return day; } public void setDay(Date day) { this.day = day; } public double getAmountMoney() { return amountMoney; } public void setAmountMoney(double amountMoney) { this.amountMoney = amountMoney; } public int getBusinessNum() { return businessNum; } public void setBusinessNum(int businessNum) { this.businessNum = businessNum; } public int getBalanceNum() { return balanceNum; } public void setBalanceNum(int balanceNum) { this.balanceNum = balanceNum; } public String getCreateTime() { return createTime; } public void setCreateTime(String createTime) { this.createTime = createTime; } public Integer getType() { return type; } public void setType(Integer type) { this.type = type; } public String getModifyTime() { return modifyTime; } public void setModifyTime(String modifyTime) { this.modifyTime = modifyTime; } @Override public String toString() { return JSON.toJSONString(this); } @Override public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } }
运行结果:
clone方法拷贝10万个简单对象,耗时====0
四、总结
通过以上测试,我们可以发现传统的get、set方法,复制10万个基本对象耗时15毫秒,以此为标准,jsonstring方式耗时大约稳定在getset方法的20倍左右。再次是beanutils方法,耗时基本稳定在getset方法的200倍左右,此方法不建议使用,因为它的功能使用json可以完全代替,而它的耗时最长。最后,重写clone方法来拷贝对象效率是最高的,但实现不易,复杂对象的拷贝需使所有子对象都实现clone方法,实际项目中较少使用。
以上是拷贝简单对象的四种方法及各自性能分析。

浙公网安备 33010602011771号