三种实现深拷贝的方式以及性能比较

Posted 1341969602-wwddz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三种实现深拷贝的方式以及性能比较相关的知识,希望对你有一定的参考价值。

这里的深拷贝指的是我们根据一个对象获得另一个内容一样的对象,并且新的对象是指向旧对象的内容的地址而不是就对象的栈对象的地址,或者就是完全开辟新的地址空间存储同样的内容

在这三个方式之前,我想给两个例子,平时使用remove和filter都会遇到的问题

@Test
    void mmm() 
        List<Long> a = new ArrayList<>();
        a.add(1L);
        a.add(2L);
        System.out.println("--------a -------------");
        a.forEach(System.out::println);
        List<Long> b = new ArrayList<>();
        b.add(3L);
        b.add(4L);
        System.out.println("--------b -------------");
        b.forEach(System.out::println);
        a.addAll(b);
        System.out.println("--------a 加上b之后-------------");
        a.forEach(System.out::println);
        b.removeIf(v -> v == 3L);
        System.out.println("--------a 在 b remove if 3 之后的结果-------------");
        a.forEach(System.out::println);
        System.out.println("--------b 在 b remove if 3 之后的结果-------------");
        b.forEach(System.out::println);
        System.out.println("--------remove if 对于结果的改变测试完毕-------------");
    
--------a -------------
1
2
--------b -------------
3
4
--------a 加上b之后-------------
1
2
3
4
--------a 在 b remove if 3 之后的结果-------------
1
2
3
4
--------b 在 b remove if 3 之后的结果-------------
4
--------remove if 对于结果的改变测试完毕-------------


@Test
    void nnn() 
        List<Long> a = new ArrayList<>();
        a.add(1L);
        a.add(2L);
        System.out.println("--------a -------------");
        a.forEach(System.out::println);
        List<Long> b = new ArrayList<>();
        b.add(3L);
        b.add(4L);
        System.out.println("--------b -------------");
        b.forEach(System.out::println);
        a.addAll(b);
        System.out.println("--------a 加上b之后-------------");
        a.forEach(System.out::println);
        b = b.stream().filter(v -> v == 3L).collect(Collectors.toList());
        System.out.println("--------a 在 b filter 3 之后的结果-------------");
        a.forEach(System.out::println);
        System.out.println("--------b 在 b filter 3 之后的结果-------------");
        b.forEach(System.out::println);
        System.out.println("--------filter 对于结果的改变测试完毕-------------");
    

--------a -------------
1
2
--------b -------------
3
4
--------a 加上b之后-------------
1
2
3
4
--------a 在 b filter 3 之后的结果-------------
1
2
3
4
--------b 在 b filter 3 之后的结果-------------
3
--------filter 对于结果的改变测试完毕-------------

 可以看出我们平时在业务比较复杂的时候,例如需要旧对象也需要新对象,name就要考虑到对象拷贝的问题了,下面开始

 

我们会有一个java bean
public class LongBean implements Serializable 
    private Long aLong;
    private static final long serialVersionUID = 1L;
    public Long getaLong() 
        return aLong;
    

    public void setaLong(Long aLong) 
        this.aLong = aLong;
    


生成集合
List<LongBean> addList() 
        List<LongBean> longList = new ArrayList<>();
        for (long i= 0 ; i < 100000 ; i++) 
            LongBean longBean = new LongBean();
            longBean.setaLong(i);
            longList.add(longBean);
        
        return longList;
    

 接下来会有三种方式以及性能比较

 

    /**
     * 通过beanUtils实现
     */
    @Test
    void testDeepCopyMethodOne() 
        long a = 0;
        for (int i = 0 ;i < 1000 ; i++ ) 
            List<LongBean> longList = addList();
            List<LongBean> newList = new ArrayList<>();
            long start = System.currentTimeMillis();
            longList.forEach(v -> 
                LongBean longBean = new LongBean();
                BeanUtils.copyProperties(v,longBean);
                newList.add(longBean);
            );
            long end = System.currentTimeMillis();
            a += (end - start);
        
        System.out.println(a);
    

 测试时间

技术图片

 

/**
     * 原本是想用addAll来实现的,但是IDEA给我推荐通过构造器实现
     */
    @Test
    void testDeepCopyMethodTwo() 
        long a = 0;
        for (int i = 0 ;i < 1000 ; i++ ) 
            List<LongBean> longList = addList();
            long start = System.currentTimeMillis();
            List<LongBean> newList = new ArrayList<>(longList);
            long end = System.currentTimeMillis();
            a += (end - start);
        
        System.out.println(a);
    

 测试时间

技术图片

 

 

/**
     * 网传的深拷贝的实现方法
     */
    @Test
    void testDeepCopyMethodThree() 
        long a = 0;
        for (int i = 0 ;i < 1000 ; i++ ) 
            List<LongBean> longList = addList();
            List<LongBean> newList = new ArrayList<>();
            long start = System.currentTimeMillis();
            try 
                ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
                ObjectOutputStream out = new ObjectOutputStream(byteOut);
                out.writeObject(longList);
                ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
                ObjectInputStream in = new ObjectInputStream(byteIn);
                newList = (List<LongBean>) in.readObject();
             catch (Exception e) 
                e.printStackTrace();
            
            long end = System.currentTimeMillis();
            a += (end - start);
        
        System.out.println(a);
    

 测试时间

 

技术图片

 

 

分析:

第一种方法是我临时想到的,因为大家平时coding的时候复制对象的时候经常用,所以这种方案从某种程度上来讲不是不行,查看源码,大致能看出,是通过对反射来处理相关的属性和值的

第二种方法一开始是准备用addAll的,这个是直接实例化来比较,还慢了,我估计多出来的时间就是数组拷贝的时间了

第三种方法是网传的深拷贝的方法,根据纸面上数据来看的话,开流确实慢滴很阿

以上是关于三种实现深拷贝的方式以及性能比较的主要内容,如果未能解决你的问题,请参考以下文章

实现深拷贝?

实现深拷贝?

实现深拷贝?

实现深拷贝?

js 浅拷贝有大用

实现深拷贝,面试看