美文网首页
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