Java - Use Arrays.asList to List limit

我們都知道當要將array轉換成List來使用時,可以使用Arrays.asList來轉換,但是這時回傳

回去的並不是java.util.ArrayList而是Arrays的內部私有類別ArrayList,它也繼承了ArrayList

的父類別AbstractList,因此原則上ArrayList的method幾乎它都可以呼叫! (如add, remove, size

等)

不過,但它繼承了AbstractList卻沒有全部都override掉,因此當呼叫add method想要增加

element時,卻拋出了java.lang.UnsupportedOperationException在

at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at ArrayList_sample.main(ArrayList_sample.java:37)

也就是原本AbstractList內的add method本身就寫了throw new UnsupportedOperationException();

而這個內部定義的ArrayList又沒有覆寫掉add,因此,呼叫add會呼叫到父類別本身的。

由Arrays.asList回傳的list來看,本身它就不支援add, remove動作來動態增加list,純粹有點像

是在操作array本身,也就是當呼叫get method,也只是以array來取值回傳,如下:

public E get(int index) {
            return a[index];
}

也如同官網上所敘述的當使用asList時

Returns a fixed-size list backed by the specified array.

此時我們能想到的就是擺脫以AbstractList為呼叫的method實體,若是ArrayList的話就能

夠以它覆寫過後重新定義的method來操作

因此我用list呼叫了subList(AbstractList method)所回傳的List,但在呼叫add後還是出現一樣

的exception。原因出在AbstractList下的subList會判斷當下的實體型態,因為此list為

Arrays.java - 2834行
private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
....

因此勢必在this instanceof RandomAccess會成立

public List<E> subList(int fromIndex, int toIndex) {
        return (this instanceof RandomAccess ?
                new RandomAccessSubList<>(this, fromIndex, toIndex) :
                new SubList<>(this, fromIndex, toIndex));
}

再追朔到

class RandomAccessSubList<E> extends SubList<E> implements RandomAccess {
    RandomAccessSubList(AbstractList<E> list, int fromIndex, int toIndex) {
        super(list, fromIndex, toIndex);
    }

    public List<E> subList(int fromIndex, int toIndex) {
        return new RandomAccessSubList<>(this, fromIndex, toIndex);
    }
}

super又呼叫SubList做初始化,因此帶進來的實體已為AbstractList內部類別SubList

在呼叫add之後,由於SubList沒定義,因此呼叫AbstractList的

public boolean add(E e) {
        add(size(), e);
        return true;
}

再來呼叫的add(size(), e);已是SubList的method而非AbstractList的

public void add(int index, E element) {
        rangeCheckForAdd(index);
        checkForComodification();
        l.add(index+offset, element);
        this.modCount = l.modCount;
        size++;
}

一切看起來好像已有動態list的樣子,但當呼叫l.add時又回到呼叫AbstractList的method

導致又拋出例外,原因在於呼叫super帶入的第一個參數的實體為AbstractList

SubList(AbstractList<E> list, int fromIndex, int toIndex) {
       .....
        l = list;
        offset = fromIndex;
        size = toIndex - fromIndex;
        this.modCount = l.modCount;
  }

最後,能夠處理的方式還可以利用一開始的list (Arrays.asList所回傳)透過新new一ArrayList

做初始化帶入值得到新的List

List<String> newList = new ArrayList<String>(list);

如此一來newList就可以使用ArrayList內的相關method進行動態操作了

PS. 以上的片段程式碼出自Java Source code

留言