ArrayList removeRange方法分析


    《ArrayList原碼分析》一文中提到了“為什么removeRange(int fromIndex,int toIndex)是protected的?”

    先給出removeRange(int fromIndex,int toIndex)方法的源碼(這段代碼是干什么的就不再解釋了,源碼分析一文中已經說明)

 1 protected void removeRange(int fromIndex, int toIndex) {
 2     modCount++;
 3     int numMoved = size - toIndex;
 4         System.arraycopy(elementData, toIndex, elementData, fromIndex,
 5                          numMoved);
 6 
 7     // Let gc do its work
 8     int newSize = size - (toIndex-fromIndex);
 9     while (size != newSize)
10         elementData[--size] = null;
11     }

    可以看明白removeRange方法將制定范圍內的元素都“刪除”了,為什么這個方法不暴露給用戶使用呢?

    上網查了部分資料,靠譜一點的解釋如下:http://stackoverflow.com/questions/2289183/why-is-javas-abstractlists-removerange-method-protected

    再結合例子去驗證,看一下代碼及執行結果:

1 public static void main(String[] args) {
2         ArrayList<Integer> ints = new ArrayList<Integer>(Arrays.asList(0, 1, 2,
3                 3, 4, 5, 6));
4         // fromIndex low endpoint (inclusive) of the subList
5         // toIndex high endpoint (exclusive) of the subList
6         ints.subList(2, 4).clear();
7         System.out.println(ints);
8     }

    運行結果為:[0, 1, 4, 5, 6]

    有沒有發現這個結果就像是調用了removeRange(2,4)!這是怎么回事?接着看!

    由於ArrayList並沒有實現subList(int fromIndex,int toIndex)方法,所以調用的是父類的方法。看到父類AbstractList的subList方法:

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

    ArrayList實現了RandomAccess接口(可以看《ArrayList原碼分析》),所以返回RandAccessSubList<E>(this,fromIndex,toIndex)。this、fromIndex、toIndex在上例中分別是ints、2、4。

    下面是RandAccessSubList<E>(this,fromIndex,toIndex)的源碼。

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

    只是調用了父類的構造方法。下面給出被調用的構造方法。

 1 SubList(AbstractList<E> list, int fromIndex, int toIndex) {
 2         if (fromIndex < 0)
 3             throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
 4         if (toIndex > list.size())
 5             throw new IndexOutOfBoundsException("toIndex = " + toIndex);
 6         if (fromIndex > toIndex)
 7             throw new IllegalArgumentException("fromIndex(" + fromIndex +
 8                                                ") > toIndex(" + toIndex + ")");
 9         l = list;
10         offset = fromIndex;
11         size = toIndex - fromIndex;
12         expectedModCount = l.modCount;
13     }

    至此subList方法調用結束。接着看clear()方法。由於subList方法返回的是List<E>所以該clear方法將調用AbstractList類的clear()方法。

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

    終於看到removeRange了,看到希望了。

1 protected void removeRange(int fromIndex, int toIndex) {
2         checkForComodification();
3         l.removeRange(fromIndex+offset, toIndex+offset);
4         expectedModCount = l.modCount;
5         size -= (toIndex-fromIndex);
6         modCount++;
7     }

    這是被調用的removeRange方法,看到沒有,里面執行了l.removeRange(fromIndex+offset,toIndex+offset),知道l是誰嗎?l定義在SubList中,還記得嗲用SubList方法傳入的list嗎?還記得調用subList時傳入的this嗎?還記得大明湖畔的夏雨荷嗎?!!!跑題了~~~

    至此將進入ArrayList的removeRange(int fromIndex,int toIndex)方法。繞了一個大彎終於通過調到了這個方法,可是又有一個疑問了:調用了subList了不是通過返回的List<E>調用了clear嗎?仔細觀察會發現其實傳到SubList構造方法中並被保存的一直是原來的ArrayList,所以調用removeRange的時候毫無疑問是對原先的List進行了處理!!!

    在結合那段英文的解釋,為了避免冗余......所以沒對用戶開放,當然你可以繼承ArrayList編寫自己的List類來調用這個方法。

    終於真相大白了哈哈哈哈哈。是的,真相永遠只有一個!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM