java之深入理解List.subList()方法

lvxiangan發表於2018-09-04

removeRange(int, int);這個方法AbstractList並沒有暴露出來,我們應該如何得到一個截短的list?

1 如何得到一個list某個範圍的子集sublist

首先想到sublist(int, int)方法 
注意此方法引數左閉右開。 
測試如下

1.1 修改sublist會影響原來的list

    LinkedList<String> ll = new LinkedList<>();
    ll.add("a");
    ll.add("b");
    ll.add("c");
    List<String> l2 =  ll.subList(1, 2);
    l2.add("new");
    System.out.println(ll);
    System.out.println(l2);

[a, b, new, c] 
[b, new] 
可見sublist是快照,sulist插入會影響原list

1.2 修改原list,則sublist的所有操作會報錯

    LinkedList<String> ll = new LinkedList<>();
    ll.add("a");
    ll.add("b");
    ll.add("c");
    List<String> l2 =  ll.subList(1, 2);//[)
    ll.add("d");
    System.out.println(ll);
    System.out.println(l2);

Exception in thread “main” java.util.ConcurrentModificationException 
at java.util.SubList.checkForComodification(AbstractList.java:769) 
可見如果更改了原來的list,sublist的任何操作都會報錯,包括get() size(),listIterator()等所有呼叫checkForComodification()的地方。

2 如何正確的截斷一個List?

subList()返回的是List!是Sublist,而不是原來的型別。

2.1在java.util.AbstractList.subList(int fromIndex, int toIndex)的定義,返回的是java.util.SubList.SubLis:

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

2.2 LinkedList並沒有覆蓋這個方法.ArryList自己覆蓋了這個方法,返回的是java.util.ArrayList.SubList:

    public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }
    宣告:
    private class SubList extends AbstractList<E> implements RandomAccess {}

看來ArryList處處體現出RandomAccess介面的特性——支援隨機訪問。

2.3 我們看一下java.util.AbstractList.clear()方法,這正是我們需要的,Sublist的clear就是這個方法

    public void clear() {
        removeRange(0, size());
    }

2.3.1 ArrayList的覆蓋

    public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

 

2.3.2 LinkedList的覆蓋

    public void clear() {
        for (Node<E> x = first; x != null; ) {
            Node<E> next = x.next;
            x.item = null;
            x.next = null;
            x.prev = null;
            x = next;
        }
        first = last = null;
        size = 0;
        modCount++;
    }

3 根據1和2

截短一個List的正確姿勢:

list.subList(from, to).clear();

 

總之: 
subList是返回一個映象而不是新示例 用了 得保證原來的list不能更改。 
之前的拋異常是因為更改了原來的list而要使用sublist的時候必然報異常。 
clear的這個跟這個問題說的是如何獲得一個list的某一段順便釋放其他節點。 
這個操作後原來的list會擷取出來 型別不變。 
而subList實際上返回的是java.util.Sublist或者java.util.ArrayList.Sublist。

 

轉自:https://blog.csdn.net/kkgbn/article/details/71169680

相關文章