JDK7集合框架原始碼學習-ArrayList(4)SubList

壹頁書發表於2016-07-11
原始碼鎮樓

  1. public List<E> subList(int fromIndex, int toIndex) {  
  2.     subListRangeCheck(fromIndex, toIndex, size);  
  3.     return new SubList(this0, fromIndex, toIndex);  
  4. }  
  5.   
  6. static void subListRangeCheck(int fromIndex, int toIndex, int size) {  
  7.     if (fromIndex < 0)  
  8.         throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);  
  9.     if (toIndex > size)  
  10.         throw new IndexOutOfBoundsException("toIndex = " + toIndex);  
  11.     if (fromIndex > toIndex)  
  12.         throw new IllegalArgumentException("fromIndex(" + fromIndex +  
  13.                                            ") > toIndex(" + toIndex + ")");  
  14. }  
  15.   
  16. private class SubList extends AbstractList<E> implements RandomAccess {  
  17.     private final AbstractList<E> parent;  
  18.     private final int parentOffset;  
  19.     private final int offset;  
  20.     int size;  
  21.   
  22.     SubList(AbstractList<E> parent,  
  23.             int offset, int fromIndex, int toIndex) {  
  24.         this.parent = parent;  
  25.         this.parentOffset = fromIndex;  
  26.         this.offset = offset + fromIndex;  
  27.         this.size = toIndex - fromIndex;  
  28.         this.modCount = ArrayList.this.modCount;  
  29.     }  
  30.   
  31.     public E set(int index, E e) {  
  32.         rangeCheck(index);  
  33.         checkForComodification();  
  34.         E oldValue = ArrayList.this.elementData(offset + index);  
  35.         ArrayList.this.elementData[offset + index] = e;  
  36.         return oldValue;  
  37.     }  
  38.   
  39.     public E get(int index) {  
  40.         rangeCheck(index);  
  41.         checkForComodification();  
  42.         return ArrayList.this.elementData(offset + index);  
  43.     }  
  44.   
  45.     public int size() {  
  46.         checkForComodification();  
  47.         return this.size;  
  48.     }  
  49.   
  50.     public void add(int index, E e) {  
  51.         rangeCheckForAdd(index);  
  52.         checkForComodification();  
  53.         parent.add(parentOffset + index, e);  
  54.         this.modCount = parent.modCount;  
  55.         this.size++;  
  56.     }  
  57.   
  58.     public E remove(int index) {  
  59.         rangeCheck(index);  
  60.         checkForComodification();  
  61.         E result = parent.remove(parentOffset + index);  
  62.         this.modCount = parent.modCount;  
  63.         this.size--;  
  64.         return result;  
  65.     }  
  66.   
  67.     protected void removeRange(int fromIndex, int toIndex) {  
  68.         checkForComodification();  
  69.         parent.removeRange(parentOffset + fromIndex,  
  70.                            parentOffset + toIndex);  
  71.         this.modCount = parent.modCount;  
  72.         this.size -= toIndex - fromIndex;  
  73.     }  
  74.   
  75.     public boolean addAll(Collection<? extends E> c) {  
  76.         return addAll(this.size, c);  
  77.     }  
  78.   
  79.     public boolean addAll(int index, Collection<? extends E> c) {  
  80.         rangeCheckForAdd(index);  
  81.         int cSize = c.size();  
  82.         if (cSize==0)  
  83.             return false;  
  84.   
  85.         checkForComodification();  
  86.         parent.addAll(parentOffset + index, c);  
  87.         this.modCount = parent.modCount;  
  88.         this.size += cSize;  
  89.         return true;  
  90.     }  
  91.   
  92.     public Iterator<E> iterator() {  
  93.         return listIterator();  
  94.     }  
  95.   
  96.     public ListIterator<E> listIterator(final int index) {  
  97.         checkForComodification();  
  98.         rangeCheckForAdd(index);  
  99.         final int offset = this.offset;  
  100.   
  101.         return new ListIterator<E>() {  
  102.             int cursor = index;  
  103.             int lastRet = -1;  
  104.             int expectedModCount = ArrayList.this.modCount;  
  105.   
  106.             public boolean hasNext() {  
  107.                 return cursor != SubList.this.size;  
  108.             }  
  109.   
  110.             @SuppressWarnings("unchecked")  
  111.             public E next() {  
  112.                 checkForComodification();  
  113.                 int i = cursor;  
  114.                 if (i >= SubList.this.size)  
  115.                     throw new NoSuchElementException();  
  116.                 Object[] elementData = ArrayList.this.elementData;  
  117.                 if (offset + i >= elementData.length)  
  118.                     throw new ConcurrentModificationException();  
  119.                 cursor = i + 1;  
  120.                 return (E) elementData[offset + (lastRet = i)];  
  121.             }  
  122.   
  123.             public boolean hasPrevious() {  
  124.                 return cursor != 0;  
  125.             }  
  126.   
  127.             @SuppressWarnings("unchecked")  
  128.             public E previous() {  
  129.                 checkForComodification();  
  130.                 int i = cursor - 1;  
  131.                 if (i < 0)  
  132.                     throw new NoSuchElementException();  
  133.                 Object[] elementData = ArrayList.this.elementData;  
  134.                 if (offset + i >= elementData.length)  
  135.                     throw new ConcurrentModificationException();  
  136.                 cursor = i;  
  137.                 return (E) elementData[offset + (lastRet = i)];  
  138.             }  
  139.   
  140.             public int nextIndex() {  
  141.                 return cursor;  
  142.             }  
  143.   
  144.             public int previousIndex() {  
  145.                 return cursor - 1;  
  146.             }  
  147.   
  148.             public void remove() {  
  149.                 if (lastRet < 0)  
  150.                     throw new IllegalStateException();  
  151.                 checkForComodification();  
  152.   
  153.                 try {  
  154.                     SubList.this.remove(lastRet);  
  155.                     cursor = lastRet;  
  156.                     lastRet = -1;  
  157.                     expectedModCount = ArrayList.this.modCount;  
  158.                 } catch (IndexOutOfBoundsException ex) {  
  159.                     throw new ConcurrentModificationException();  
  160.                 }  
  161.             }  
  162.   
  163.             public void set(E e) {  
  164.                 if (lastRet < 0)  
  165.                     throw new IllegalStateException();  
  166.                 checkForComodification();  
  167.   
  168.                 try {  
  169.                     ArrayList.this.set(offset + lastRet, e);  
  170.                 } catch (IndexOutOfBoundsException ex) {  
  171.                     throw new ConcurrentModificationException();  
  172.                 }  
  173.             }  
  174.   
  175.             public void add(E e) {  
  176.                 checkForComodification();  
  177.   
  178.                 try {  
  179.                     int i = cursor;  
  180.                     SubList.this.add(i, e);  
  181.                     cursor = i + 1;  
  182.                     lastRet = -1;  
  183.                     expectedModCount = ArrayList.this.modCount;  
  184.                 } catch (IndexOutOfBoundsException ex) {  
  185.                     throw new ConcurrentModificationException();  
  186.                 }  
  187.             }  
  188.   
  189.             final void checkForComodification() {  
  190.                 if (expectedModCount != ArrayList.this.modCount)  
  191.                     throw new ConcurrentModificationException();  
  192.             }  
  193.         };  
  194.     }  
  195.   
  196.     public List<E> subList(int fromIndex, int toIndex) {  
  197.         subListRangeCheck(fromIndex, toIndex, size);  
  198.         return new SubList(this, offset, fromIndex, toIndex);  
  199.     }  
  200.   
  201.     private void rangeCheck(int index) {  
  202.         if (index < 0 || index >= this.size)  
  203.             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));  
  204.     }  
  205.   
  206.     private void rangeCheckForAdd(int index) {  
  207.         if (index < 0 || index > this.size)  
  208.             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));  
  209.     }  
  210.   
  211.     private String outOfBoundsMsg(int index) {  
  212.         return "Index: "+index+", Size: "+this.size;  
  213.     }  
  214.   
  215.     private void checkForComodification() {  
  216.         if (ArrayList.this.modCount != this.modCount)  
  217.             throw new ConcurrentModificationException();  
  218.     }  
  219. }  

ArrayList的subList方法,首先呼叫subListRangeCheck方法做了一個範圍檢查.
然後建立並返回了一個SubList的內部類物件.

仔細對比SubList和ArrayList的定義.
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

private class SubList extends AbstractList<E> implements RandomAccess

他們同樣繼承了AbstractList,並實現了RandomAccess標記介面.
而AbstractList是一個抽象類,除了一些抽象方法,還有一些方法乾脆沒有實現.
比如:
  1. abstract public E get(int index);  
  2. public E set(int index, E element) {  
  3.     throw new UnsupportedOperationException();  
  4. }  
  5.   
  6. public void add(int index, E element) {  
  7.     throw new UnsupportedOperationException();  
  8. }  
  9.   
  10. public E remove(int index) {  
  11.     throw new UnsupportedOperationException();  
  12. }  


在建立SubList內部類的時候,
new SubList(this, 0, fromIndex, toIndex);
實際上將外部的ArrayList物件,傳入了內部類作為一個資料成員,即 AbstractList parent
並且記錄了偏移量和Size等資訊.

  1. private final AbstractList<E> parent;  
  2. private final int parentOffset;  
  3. private final int offset;  
  4. int size;  
  5.   
  6. SubList(AbstractList<E> parent,  
  7.         int offset, int fromIndex, int toIndex) {  
  8.     this.parent = parent;  
  9.     this.parentOffset = fromIndex;  
  10.     this.offset = offset + fromIndex;  
  11.     this.size = toIndex - fromIndex;  
  12.     this.modCount = ArrayList.this.modCount;  
  13. }  

SubList的方法呼叫,使用了兩種方式
1.因為內部類可以訪問外部類的方法和屬性,所以一些操作直接使用外部類的方法
2.由於內部類AbstractList parent指向外部類的物件,有一些操作呼叫parent的方法,透過多型性呼叫了外部類的方法.

程式碼風格似乎不太統一..

add和remove都是呼叫抽象類的方法,透過多型性呼叫了ArrayList的方法
  1. public void add(int index, E e) {  
  2.     rangeCheckForAdd(index);  
  3.     checkForComodification();  
  4.     parent.add(parentOffset + index, e);  
  5.     this.modCount = parent.modCount;  
  6.     this.size++;  
  7. }  
  8.   
  9. public E remove(int index) {  
  10.     rangeCheck(index);  
  11.     checkForComodification();  
  12.     E result = parent.remove(parentOffset + index);  
  13.     this.modCount = parent.modCount;  
  14.     this.size--;  
  15.     return result;  
  16. }  

而get和set方法,又是透過內部類可以直接訪問外部類的特性.
  1. public E set(int index, E e) {  
  2.     rangeCheck(index);  
  3.     checkForComodification();  
  4.     E oldValue = ArrayList.this.elementData(offset + index);  
  5.     ArrayList.this.elementData[offset + index] = e;  
  6.     return oldValue;  
  7. }  
  8.   
  9. public E get(int index) {  
  10.     rangeCheck(index);  
  11.     checkForComodification();  
  12.     return ArrayList.this.elementData(offset + index);  
  13. }  

有點意思.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-2121834/,如需轉載,請註明出處,否則將追究法律責任。

相關文章