序言:許多人看完,ArrayList源碼後,自我感受良好,一問 RandomAccess 這玩意幹嗎的,一臉懵,java
因此今天來盤盤這個接口算法
咱先看看官方怎麼介紹這個接口的,摘自注釋數組
譯:這個接口是被用來List實現的標記接口,支持快速隨機訪問,且只要你實現了它,你使用for循環遍歷,效率會高於迭代器的遍歷(說明一下,這裏說的 for 循環是普通循環,而 加強 for-each 本質就等同於 迭代器遍歷)數據結構
//避免自動裝箱拆箱影響,不聲明泛型 List list = new ArrayList<>(); int total = 40000000; for (int i = 0; i<total; i++){ list.add(i); } //1.使用普通for循環的效率 long start1 = System.currentTimeMillis(); for(int i = 0; i < total; i++){ Object temp = list.get(i); } long end1 = System.currentTimeMillis(); System.out.println("普通循環的時間效率:" + (end1 - start1)); //2.使用迭代器的循環效率 long start2 = System.currentTimeMillis(); Iterator iterator = list.iterator(); while(iterator.hasNext()){ Object temp = iterator.next(); } long end2 = System.currentTimeMillis(); System.out.println("迭代器循環的時間效率:" + (end2 - start2)); //3.使用加強for循環(其實底層也是用迭代器玩的) long start3 = System.currentTimeMillis(); for(Object num: list){ Object temp = num; } long end3 = System.currentTimeMillis(); System.out.println("加強for循環的時間效率:" + (end3 - start3));
這裏的隨機訪問,就是可以隨機的訪問 List 中的任何一個元素,不要想多dom
雖然全部的 List 實現 都支持隨機訪問,只是因爲數據結構不一樣,致使訪問效率不一樣。可是這裏的快速隨機訪問,不是全部 List 集合能幹的。測試
因此 ArrayList 實現了 RandomAccess
,LinkedList 則沒有code
實現了 RandomAccess 的接口有:對象
可能你看到這,又有疑問了,我知道這個接口是標誌接口了,實現了它就能快速隨機訪問,因此它有什麼用 ?blog
在上文中,咱們經過測試發現只要實現了這個接口,普通 for 循環的 效率要高於迭代器,因此你可能會說在追求效率的時候我全用 普通 for循環 就好了,這個接口的做用仍是沒有凸顯出來。接口
那麼下面咱們看這樣一個測試, 此次測試對象爲 LinkedList。
//注意此次咱們使用雙線鏈表LinkedList List list = new LinkedList(); int total = 100000; for (int i = 0; i<total; i++){ list.add(i); } //1.使用普通for循環的效率 long start1 = System.currentTimeMillis(); for(int i = 0; i < total; i++){ Object temp = list.get(i); } long end1 = System.currentTimeMillis(); System.out.println("普通循環的時間效率:" + (end1 - start1)); //2.使用迭代器的循環效率 long start2 = System.currentTimeMillis(); Iterator iterator = list.iterator(); while(iterator.hasNext()){ Object temp = iterator.next(); } long end2 = System.currentTimeMillis(); System.out.println("迭代器循環的時間效率:" + (end2 - start2));
明白了不,不一樣 List 集合 使用不一樣的遍歷方式,效率完徹底全不同,不是使用誰效率就必定高,得看對象是誰
因此若是你有這麼個訴求,你有個List 對象 A,可是它多是 LinkedList,多是ArrayList,也多是 CopyOnWriteArrayList,可是你就想它是以最高效率去遍歷的,這個時候你能夠根據這個RandomAccess 去決定以哪一種方式去遍歷
if(A instanceof RandomAccess){ //使用普通for循環遍歷 } else { //使用迭代器遍歷 }
上文咱們提到有沒有實現 RandomAccess接口,會致使不一樣的集合採起不一樣的遍歷方式,會有不同的訪問效率。可是爲何會這樣呢,底層是怎麼作的
咱們看一下 java.util.Collections#binarySearch
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key) { if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD) return Collections.indexedBinarySearch(list, key); else return Collections.iteratorBinarySearch(list, key); }
咱們能夠看到,在進行二分查找時,會進行判斷是否實現了 RandomAccess接口 從而採起不同的遍歷方式
因此看到這你應該明白了,數據結構決定了算法的根本,RandomAccess接口 僅僅是個標誌接口
不只是二分查找,底層的普通遍歷也會根據其數據結構選擇相應的執行策略,選對了和數據結構相性匹配的策略固然就快了
總結:數據結構決定算法