java.util.Collections.copy():列表List淺拷貝

今天同事問我怎樣將一個列表(list1)拷貝到另外一個列表(list2),而後修改新的列表(list2)不會影響到舊的列表(list1),想了一想,這是深拷貝啊。java

但是,除了循環new還有別的辦法嗎,想了又想,本身也是啥都不懂啊,趕忙百度學習一下,因而就找到了java.util.Collections.copy(),一開始還覺得這個是個深拷貝呢,沒想到仍是個淺拷貝。雖然還沒找到深拷貝的方法去解決同事的問題,但仍是要學習一下這個淺拷貝,畢竟也是有用滴。數組

先寫個單元測試試一下:dom

@Test
public void testCollectionsCopy() {
    List<String> srcList = new ArrayList<>();
    srcList.add("張三");
    srcList.add("李四");
    srcList.add("王五");

    List<String> descList = new ArrayList<>(3);
    
    Collections.copy(descList, srcList);

    for (String desc : descList) {
        System.out.println(desc);
    }
} 

結果報錯,悲劇了:java.lang.IndexOutOfBoundsException: Source does not fit in dest。下標越界啊。單元測試

趕忙看看java.util.Collections.copy()的源碼壓壓驚。學習

public static <T> void copy(List<? super T> dest, List<? extends T> src) {
        int srcSize = src.size();
        if (srcSize > dest.size())
            throw new IndexOutOfBoundsException("Source does not fit in dest");

        if (srcSize < COPY_THRESHOLD ||
            (src instanceof RandomAccess && dest instanceof RandomAccess)) {
            for (int i=0; i<srcSize; i++)
                dest.set(i, src.get(i));
        } else {
            ListIterator<? super T> di=dest.listIterator();
            ListIterator<? extends T> si=src.listIterator();
            for (int i=0; i<srcSize; i++) {
                di.next();
                di.set(si.next());
            }
        }
    } 

經過看源碼,發現這個方法是有目標數組和源數組的元素個數進行比較的操做,若是目標數組的元素個數小於源數組的元素個數,則拋出下標越界的異常。測試

但是我已經指定了descList的容量爲3了呀!難道這個容量不等於實際元素個數嗎?經過打印descList.size()才發現,descList的實際元素個數爲0。這樣我就知道,指定的descList容量爲3,只是指定了descList當前容納的元素個數爲3,即descList的容納能力(Capacity)爲3,並不表明descList中有了三個實際的元素。初始化時實際元素個數(Size)永遠爲0,只有在進行add()和remove()等相關操做時,實際元素個數纔會發生改變。spa

好吧,元兇找到了。只要給descList塞一些空對象就完事了。code

@Test
public void testCollectionsCopy() {
    List<String> srcList = new ArrayList<>();
    srcList.add("張三");
    srcList.add("李四");
    srcList.add("王五");

    List<String> descList = new ArrayList<>(3);
    descList.add(null);
    descList.add(null);
    descList.add(null);
    descList.add("趙六");
    System.out.println(descList.size());

    Collections.copy(descList, srcList);

    for (String desc : descList) {
        desc = desc + "是笨蛋";
        System.out.println(desc);
    }
}

這裏能夠發現,給descList指定容量好像並無什麼用,由於ArrayList是可變更態數組隊列(底層實現是Array數組),長度會隨着實際元素個數自動增大,那麼究竟是有什麼用呢?(保留疑問,這個要看看Java的集合惡補一下知識啦,或者有沒有大佬告訴我一下啊)對象

也能夠中JDK7中新增長的方法Array.asList()來實現,即數組轉List。blog

@Test
public void testCollectionsCopy() {
    List<String> srcList = new ArrayList<>();
    srcList.add("張三");
    srcList.add("李四");
    srcList.add("王五");

    List<String> descList = Arrays.asList(new String[srcList.size()]);
    System.out.println(descList.size());

    Collections.copy(descList, srcList);

    for (String desc : descList) {
        desc = desc + "是笨蛋";
        System.out.println(desc);
    }
}

其實也能夠用addAll()。

@Test
public void testCollectionsCopy() {
    List<String> srcList = new ArrayList<>();
    srcList.add("張三");
    srcList.add("李四");
    srcList.add("王五");

    List<String> descList = new ArrayList<>();
    descList.addAll(srcList);
    System.out.println(descList.size());

    for (String desc : descList) {
        desc = desc + "是笨蛋";
        System.out.println(desc);
    }
}

嘻嘻,就這些了,接着找找深拷貝的知識吧,順便還要總結下淺拷貝和深拷貝的知識呢。

 

"願你既能夠安於朝九晚五,波瀾不驚;又能隨時出發,踏浪遠航。"

相關文章
相關標籤/搜索