美文网首页
Java集合类的复制

Java集合类的复制

作者: 向天葵 | 来源:发表于2019-08-07 10:48 被阅读0次

使用构造方法复制

java ArrayList构造方法中,存在这样一个构造函数

public ArrayList(Collection<? extends E> c)

利用一个集合,构造出一个新的ArrayList。这样就可以新建出一个和原来的集合相同的ArrayList。但是,需要注意的是,两个集合中的元素其实所指的对象是同一个,这种复制方法仅仅是复制了引用而已。
另外,addAll方法也是一样,添加的仅仅是引用,不会克隆对象。

    @Test
    public void listAdd() {
        List<Result> list = new ArrayList<Result>();
        list.add(new Result("1"));
        list.add(new Result("2"));
        list.add(new Result("3"));

        List<Result> listCp = new ArrayList<Result>(list);
        
        list.get(0).setMsg("ch");
        for (Result result : listCp) {
            System.out.println(result.getMsg());
                       
        }
               //将会输出  ch,2,3
//
//      List<Result> listCp = new ArrayList<Result>();
//      listCp.addAll(list);
//      list.get(0).setMsg("ch");
//      for (Result result : listCp) {
//          System.out.println(result.getMsg());
//      }
            //将会输出  ch,2,3
    }

包装类型集合复制

包装类型由于自动装箱的缘故,复制后的集合与复制前的集合所指向的并非同一个内存对象,具体原因也不理解,先埋个坑。

    @Test
    public void longTest() {
        List<Long> longList = new ArrayList<Long>();
        
        longList.add(1L);
        longList.add(2L);
        longList.add(3L);
        longList.add(4L);
        
        
        List<Long> cpLong = new ArrayList<Long>(longList);
        longList.set(0, 23L);
        for (Long long1 : cpLong) {
            System.out.println(long1);
        }
          //打印1,2,3,4
    }

查看源码

    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {       
              //省略部分判断语句
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

该构造方法调用Arrays的copyOf方法

   public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

而copyOf最终会调用System.copyOf的方法进行数组的复制,该复制方法只是单纯的使用如 'a=b' 这种方法进行复制,因此该构造方法传入的集合只会引用的复制。

同样地,addAll方法源码也是调用的Arrays.copyOf()方法进行集合的增加。

深拷贝和浅拷贝

普通的集合复制只是将内存中栈的地址快拷贝一份,使得一个新的集合对象指向这个地址块,但是集合中的对象变量却是指向堆中的同一块区域。所以当拷贝的集合修改了集合对象内的数据,那么源集合对象也就随之改变了,这样的效果我们称之为Java集合对象的浅复制,即只是在栈中拷贝了,而堆中的数据并没有拷贝。我们上面所说的就是浅拷。
而深度复制则是同时在栈中和堆中的数据进行拷贝,这样,其拷贝的集合和被拷贝的集合已经没有任何关系了。

深拷贝的实现方法

我们可以通过继承cloneable接口,并实现clone()方法。然后通过调用该类的clone方法便可以得到一个深拷贝的实例复制。

public class Demo {
        
    private int  demoValue;
        
    public void setDemoValue(int value){
        this.demoValue = value;
    }
        
    public int getDemoValue(){
        return this.demoValue;
    }
        
    public Demo(){
            
    }
        
    public Demo(int demoValue){
        this.demoValue = demoValue;
    }

继承接口后,clone实现的内容:

 @Override
        protected Demo clone() throws CloneNotSupportedException {          
            return (Demo)super.clone();
        }

Collections.copy()

使用这个工具方法可以针对集合的复制简便的进行复制,而且是深拷贝,但需要注意目标集合的长度不能小于源集合,否则会抛出异常。
接口:

public static <T> void copy(List<? super T> dest, List<? extends T> src)

相关文章

网友评论

      本文标题:Java集合类的复制

      本文链接:https://www.haomeiwen.com/subject/irgndctx.html