前言
实际项目中,我们常常需要对对象进行拷贝,此文将列出四种常见的对象拷贝方式,并针对它们分别做出实验进行性能分析。
此次实验用于拷贝的简单对象如下:
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);
}
}
方法一、getset方法
最原始拷贝对象的方法,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方法,实际项目中较少使用。
以上是拷贝简单对象的四种方法及各自性能分析,个人水平有限,如有意见建议,请多多留言。