Java几种深度拷贝方法效率比较

Java在复制一个对象时有浅拷贝与深拷贝之分,具体区别就不在此赘述,本文主要分析Java深拷贝的几种方法以及他们的效率高低。
1. 使用Java序列化方法 想要深拷贝一个对象,常用的方法是序列化为数据流,此方法的前提是对象以及对象中包含的子对象都要继承Serializable接口。
2. 利用Kryo序列化框架 Kryo是一个快速高效的Java序列化框架,旨在提供快速、高效和易用的API。无论文件、数据库或网络数据Kryo都可以随时完成序列化。Kryo还可以执行自动深拷贝(克隆)、浅拷贝(克隆)。这是对象到对象的直接拷贝,非对象->字节->对象的拷贝。该方法不需要继承Serializable接口。
com.esotericsoftware kryo 4.0.1

3. 利用Json转化的方法 如果对象没有继承Serializable接口,可以先将对象转化为JSON,再序列化为对象,和第一种方法类似。Json转换工具可以用Jackson或者Json-lib,本文选择Json-lib只需要在maven里面添加以下依赖:
net.sf.json-lib json-lib 2.4 jdk15

4. 手动New对象的方法 人工构建对象,如果需要复制的对象中包含非基本类型,如List,对象等结构时,可以在需要的时候手动new对象,将属性值挨个调用set方法,比较繁琐。
5. 具体实例 (1) 首先构造两个实体对象User.java和Name.java,具体代码如下
public class User implements Serializable{ private static final long serialVersionUID = -6952319891279734655L; private Name name; private String phone; private String sex; private int age; ...//此处省略get、set方法 }

public class Name implements Serializable{ private static final long serialVersionUID = -2023200990550843496L; private String firstName; private String lastName; ...//此处省略get、set方法 }

(2) 测试的主程序代码如下:
package com.test.sort.hello; /** * Created by GeekBoy on 2017/12/10. */ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import com.esotericsoftware.kryo.Kryo; import net.sf.json.JSONObject; /** * @author GeekBoy * */ public class TestCopy {public static void main(String[] args) {User source=new User(); source.setAge(25); source.setPhone("13590117892"); source.setSex("1"); Name name=new Name(); name.setFirstName("li"); name.setLastName("ming"); source.setName(name); Long before=System.currentTimeMillis(); for(int i=0; i<1000000; i++){ User tmp=copyByNewObject(source); try { //User tmp=copyImplSerializable(source); //User tmp=copyByJson(source); } catch (Exception e) { e.printStackTrace(); } } Long after=System.currentTimeMillis(); System.out.println(after-before); }/** * 深层拷贝 - 需要类继承序列化接口 * @param * @param obj * @return * @throws Exception */ @SuppressWarnings("unchecked") public static T copyImplSerializable(T obj) throws Exception { ByteArrayOutputStream baos = null; ObjectOutputStream oos = null; ByteArrayInputStream bais = null; ObjectInputStream ois = null; Object o = null; //如果子类没有继承该接口,这一步会报错 try { baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(obj); bais = new ByteArrayInputStream(baos.toByteArray()); ois = new ObjectInputStream(bais); o = ois.readObject(); return (T) o; } catch (Exception e) { throw new Exception("对象中包含没有继承序列化的对象"); } finally{ try { baos.close(); oos.close(); bais.close(); ois.close(); } catch (Exception e2) { //这里报错不需要处理 } } }/** * 深层拷贝 - 需要net.sf.json.JSONObject * @param * @param obj * @return * @throws Exception */ @SuppressWarnings("unchecked") public static T copyByJson(T obj) throws Exception { return (T)JSONObject.toBean(JSONObject.fromObject(obj),obj.getClass()); }/** * 通过new 对象的方法深拷贝 * @param source * @return */ public static User copyByNewObject(User source){ User result=new User(); result.setAge(source.getAge()); result.setPhone(source.getPhone()); result.setSex(source.getSex()); Name name=new Name(); name.setFirstName(source.getName().getFirstName()); name.setLastName(source.getName().getLastName()); result.setName(name); return result; } /** * 通过Kryo框架深拷贝 * @param source * @return */ public static User copyByKryo(User source){ Kryo kryo = new Kryo(); return kryo.copy(source); } }

6. 运行结果及效率分析
new 对象 JDK序列化 Kyro序列化 Json转化
1000次 1 237 307 477
10000次 3 914 790 1328
100000次 10 2951 1780 2604
通过上面的测试可以看出new 对象的方法是最快的,比较适合性能要求较高的场合。其次是Kyro序列化方法,Json转化的方法还有优化的余地,使用不同的Json库会有不同结果。最慢的是JDK的序列化操作,不建议用此种方案进行深度拷贝。
参考文献 【Java几种深度拷贝方法效率比较】http://blog.csdn.net/isea533/article/details/9375907
https://github.com/EsotericSoftware/kryo
镜像地址 http://www.zhangwei.wiki/#/posts/1
Java几种深度拷贝方法效率比较
文章图片

转载于:https://www.cnblogs.com/coderzhw/p/11094284.html

    推荐阅读