1. 程式人生 > >java.util.Collections.copy():列表List拷貝

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

str info 初始化 random except ati 等於 可變 結果

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

可是,除了循環new還有別的辦法嗎,想了又想,自己也是啥都不懂啊,於是趕緊百度學習一下。

於是找到了java.util.Collections.copy()

趕緊寫個單元測試試一下:

@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()等相關操作時,實際元素個數才會發生改變。

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

@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數組),長度會隨著實際元素個數自動增大,那麽到底是有什麽用呢?

也可以中JDK7中新增加的方法Array.asList()來實現,即數組轉List。

@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());

    Collections.copy(descList, srcList);

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

還有好多東西不懂,我的天。。

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