點進Collections.reverse的代碼瞄了眼,然后就開始了一些基礎知識的收集。
現在發現知道的越多,知道不知道的越多。
列幾個記錄下:
reverse方法源碼:
/** * Reverses the order of the elements in the specified list.<p> * * This method runs in linear time. * * @param list the list whose elements are to be reversed. * @throws UnsupportedOperationException if the specified list or * its list -iterator does not support the <tt>set</tt> operation. */ public static void reverse (List<?> list) { int size = list.size(); if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) { for ( int i=0, mid=size>>1, j=size-1; i<mid; i++, j--) swap(list, i, j); } else { ListIterator fwd = list.listIterator(); ListIterator rev = list.listIterator(size); for ( int i=0, mid=list.size()>>1; i<mid; i++) { Object tmp = fwd.next(); fwd.set(rev.previous()); rev.set(tmp); } } }
1,首先看見RandomAccess
將操作隨機訪問列表的最佳算法(如 ArrayList)應用到連續訪問列表(如 LinkedList)時,可產生二次項的行為。如果將某個算法應用到連續訪問列表,那么在應用可能提供較差性能的算法前,鼓勵使用一般的列表算法檢查給定列表是否為此接口的一個 instanceof,如果需要保證可接受的性能,還可以更改其行為。
現在已經認識到,隨機和連續訪問之間的區別通常是模糊的。例如,如果列表很大時,某些 List 實現提供漸進的線性訪問時間,但實際上是固定的訪問時間。這樣的 List 實現通常應該實現此接口。實際經驗證明,如果是下列情況,則 List 實現應該實現此接口,即對於典型的類實例而言,此循環:
for (int i=0, n=list.size(); i < n; i++) list.get(i);
的運行速度要快於以下循環:
for (Iterator i=list.iterator(); i.hasNext(); ) i.next();
2,標記接口(marker interface)
例如,如果沒有使用Iterator,遍歷一個數組的方法是使用索引:
for(int i=0; i<array.size(); i++) { ... get(i) ... }
客戶端都必須事先知道集合的內部結構,訪問代碼和集合本身是緊耦合,無法將訪問邏輯從集合類和客戶端代碼中分離出來,每一種集合對應一種遍歷方法,客戶端代碼無法復用。
更恐怖的是,如果以后需要把ArrayList更換為LinkedList,則原來的客戶端代碼必須全部重寫。
為解決以上問題,Iterator模式總是用同一種邏輯來遍歷集合:
for(Iterator it = c.iterater(); it.hasNext(); ) { ... }
奧秘在於客戶端自身不維護遍歷集合的"指針",所有的內部狀態(如當前元素位置,是否有下一個元素)都由Iterator來維護,而這個Iterator由集合類通過工廠方法生成,因此,它知道如何遍歷整個集合。
ListIterator可以定位當前的索引位置,nextIndex()和previousIndex()可以實現。Iterator 沒有此功能。
public static void main(String[] args) { List list =new LinkedList(); for (int i = 0; i < 100000; i++) { list.add(i); } int size = list.size(); long t1 = System.currentTimeMillis(); for ( int i=0, mid=size>>1, j=size-1; i<mid; i++, j--) swap(list, i, j); long t2 = System.currentTimeMillis(); System.out.println(t2 - t1);//結果1 long t3 = System.currentTimeMillis(); ListIterator fwd = list.listIterator(); ListIterator rev = list.listIterator(size); for ( int i=0, mid=list.size()>>1; i<mid; i++) { Object tmp = fwd.next(); fwd.set(rev.previous()); rev.set(tmp); } long t4 = System.currentTimeMillis(); System.out.println(t4 - t3);//結果2 } public static void swap(List<?> list, int i, int j) { final List l = list; l.set(i, l.set(j, l.get(i))); }
那么ArrayList 使用這兩種方式的效果呢?
測試結果相差無幾,隨着增大數據量,swap要好於ListInterator,但是有時微乎其微,所以這個reverse代碼中並沒有對大數據量的ArrayList進行swap方式,減少了代碼冗余,也沒有降低什么性能。
---------------------------------------
還有很多擴展學習的地方,繼續前進吧。