學習過數據結構的同窗都會有這樣的一個印象,ArrayList的底層是由數組操做的,它的操做本質來說是對封裝數組的操做,而LinkedList的底層則是由鏈表實現的。java
而數組因爲其地址是連續的,因此在知道了數組第一個元素的地址,再調用其它的地址,則尋址速度會在o(1)的時間裏完成,而鏈表則須要進行表的遍歷,找到符合條件的再返回,於是對於讀來說,ArrayList的速度比較快。數組
但若是進入到了添加和刪除的階段,那可就要另說了,由於數組是要緊湊着的,因此在刪除了數組中某一位置的元素,它後面的元素會依次向前移動一個單元格,保證數組不會出現空的狀況。因此會有大量的數據移動的過程,所以若是一個集合寫入和刪除操做比較頻繁,則選用LinkedList集合。數據結構
咱們爲了驗證以上的結論,能夠寫下以下的代碼:dom
public class ListVisitPerformanceCompare { public static void main(String[] args) { int totalNum = 10000; List<Integer> arrList = new ArrayList<>(); List<Integer> linkList = new LinkedList<>(); int[] idxArr = new int[totalNum]; Random random = new Random(); for (int i = 0; i < totalNum; i++) { int randInt = random.nextInt(); idxArr[i] = random.nextInt(totalNum); arrList.add(randInt); linkList.add(randInt); } calGetTimeCost(arrList, idxArr); calGetTimeCost(linkList, idxArr); } private static void calGetTimeCost(List<Integer> arrList, int[] idxArr) { int len = idxArr.length; long startTime = System.currentTimeMillis(); for (int i = 0; i < len; i++) { arrList.get(idxArr[i]); } System.out.println("在集合 :" + arrList.getClass().getName() + "下隨機抽取" + len + "條數據,耗時:" + (System.currentTimeMillis() - startTime) + "ms"); } }
如上,咱們在容量爲10000的ArrayList和LinkedList集合分別隨機訪問10000次集合中的元素,獲得的結果以下:性能
在集合 :java.util.ArrayList下隨機抽取10000條數據,耗時:1ms 在集合 :java.util.LinkedList下隨機抽取10000條數據,耗時:69ms
咱們接下來驗證第二個結論,一樣,寫下以下的代碼:學習
public class ListOperationPerformanceCompare { public static void main(String[] args) { int initialSize = 1000; // 操做多少次 int operationTime = 100000; List<Integer> arrList = new ArrayList<>(); List<Integer> linkList = new LinkedList<>(); Random random = new Random(); // 初始化集合 for (int i = 0; i < initialSize; i++) { int randInt = random.nextInt(); arrList.add(randInt); linkList.add(randInt); } int tmpSize = initialSize; Operation[] operationArr = new Operation[operationTime]; for (int i = 0; i < operationTime; i++) { int num = random.nextInt(); int operation = num & 1; tmpSize += operation == 0 ? -1 : 1; // 拒絕指針異常 if (tmpSize <= 0) { tmpSize = 1; operation = 1; } int idx = random.nextInt(tmpSize); operationArr[i] = new Operation(operation, idx, num); } calOperationCostTime(arrList, operationArr); calOperationCostTime(linkList, operationArr); } static void calOperationCostTime(List<Integer> list, Operation[] operationArr) { int len = operationArr.length; long startTime = System.currentTimeMillis(); for (int i = 0; i < len; i++) { switch (operationArr[i].operation) { case 0: list.remove(operationArr[i].idx); // list.remove(0); break; case 1: list.add(operationArr[i].idx, operationArr[i].num); // list.add(0, operationArr[i].num); break; default: } } System.out.println("在集合 :" + list.getClass().getName() + "下隨機增刪" + len + "次,耗時:" + (System.currentTimeMillis() - startTime) + "ms"); } static class Operation { public Operation(int operation, int idx, int num) { this.operation = operation; this.idx = idx; this.num = num; } /** * 0:刪除 1:添加 */ int operation; /** * 位置 */ int idx; /** * 要插入的數字(若是是插入操做) */ int num; } }
咱們運行的結果是:this
在集合 :java.util.ArrayList下隨機增刪100000次,耗時:43ms 在集合 :java.util.LinkedList下隨機增刪100000次,耗時:126ms
爲何會出現這樣的狀況呢?指針
由於鏈表在進行刪除的時候雖然只須要移動鏈表指針的地址,但要找到在哪裏進行操做倒是一個很是耗時的操做,因此LinkedList的性能主要消耗在了尋找地址上了。code
從上面的例子咱們能夠看出,若是沒有特殊的狀況,選取集合的時候優先選取ArrayList。orm