目錄
- 1.ArrayList簡介
- 2.ArrayList構造方法分析
- 3.ArrayList的add方法以及擴容機制
- 4.ArrayList常用方法
- 5.ArrayList遍歷
- 6.ArrayList的缺陷
1.ArrayList簡介
在集合框架中,ArrayList是一個普通的類,實現了List接口,具體框架圖如下:
【說明】
- ArrayList是以泛型方式實現的,使用時必須要先實例化
- ArrayList實現了RandomAccess接口,表明ArrayList支持隨機訪問
- ArrayList實現了Cloneable接口,表明ArrayList是可以clone的
- ArrayList實現了Serializable接口,表明ArrayList是支持序列化的
- 和Vector不同,ArrayList不是線程安全的,在單線程下可以使用,在多線程中可以選擇Vector或者CopyOnWriteArrayList
- ArrayList底層是一段連續的空間,并且可以動態擴容,是一個動態類型的順序表
2.ArrayList構造方法分析
ArrayList有三個構造方法
1.無參的構造方法
首先我們看到一個elementData
為ArrayList定義好的一個數組,默認為空,指數一個數組引用。然后看到DEFAULTCAPACITY_EMPTY_ELEMENTDATA
可以看到并沒有給數組分配內存。
2.帶一個int參數的構造方法(可以給ArrayList設置一個初始容量)
先看到if
判斷語句,當傳入參數大于0時,直接分配一個參數大小的空間
傳入參數等于0時與無參構造方法一樣,并不會給數組分配空間
傳入參數小于0就會拋出一個異常
3.帶一個類型變量參數的構造方法
我們先對傳入的參數進行解析Collection<? extends E> c
這樣我們就可以傳入一個ArrayList
變量,舉例如下
public static void main(String[] args) {ArrayList<Integer> arrayList=new ArrayList<>();arrayList.add(10);arrayList.add(20);ArrayList<Integer> arrayList1=new ArrayList<>(arrayList);/*傳入一個ArrayList變量,這個參數需要滿足了下幾個條件才能夠傳遞*1.ArrayList實現了Collection接口*2.參數類型是arrayList1指定的泛型本身“Integer”*/}
3.ArrayList的add方法以及擴容機制
看到上面的add方法,左邊的add方法通過調用右邊的add方法進行數據的插入操作,下面我們重點來講解左邊這個add方法
首先看到if
判斷語句,當數據的數量等于數組的長度就會調用grow方法進行擴容。
grow方法又調用了另一個grow方法
先看到if
里面的判斷語句,oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA
當數組容量初始為DEFAULTCAPACITY_EMPTY_ELEMENTDATA
(空)的時候進入else語句elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
給數組分配空間為DEFAULT_CAPACITY
和minCapacity
的最大值
看到DEFAULT_CAPACITY
的值為10,所以當數組初始空間為空時就會給數組分配一個容量為10的內存。正常進入if語句就會觸發ArrayList的擴容機制
擴容的空間大概是原來的1.5倍,通過一步一步調用上面的方法(了解)
4.ArrayList常用方法
舉例如下
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("JavaSE");
list.add("JavaWeb");
list.add("JavaEE");
list.add("JVM");
list.add("測試課程");
System.out.println(list);
// 獲取list中有效元素個數
System.out.println(list.size());
// 獲取和設置index位置上的元素,注意index必須介于[0, size)間
System.out.println(list.get(1));
list.set(1, "JavaWEB");
System.out.println(list.get(1));
// 在list的index位置插入指定元素,index及后續的元素統一往后搬移一個位置
list.add(1, "Java數據結構");
System.out.println(list);
// 刪除指定元素,找到了就刪除,該元素之后的元素統一往前搬移一個位置
list.remove("JVM");
System.out.println(list);
// 刪除list中index位置上的元素,注意index不要超過list中有效元素個數,否則會拋出下標越界異常
list.remove(list.size()-1);
System.out.println(list);
// 檢測list中是否包含指定元素,包含返回true,否則返回false
if(list.contains("測試課程")){
list.add("測試課程");
}
// 查找指定元素第一次出現的位置:indexOf從前往后找,lastIndexOf從后往前找
list.add("JavaSE");
System.out.println(list.indexOf("JavaSE"));
System.out.println(list.lastIndexOf("JavaSE"));
// 使用list中[0, 4)之間的元素構成一個新的SubList返回,但是和ArrayList共用一個elementData數組
List<String> ret = list.subList(0, 4);
System.out.println(ret);
list.clear();
System.out.println(list.size());
}
5.ArrayList遍歷
ArrayList 可以使用三方方式遍歷:for循環+下標、foreach、使用迭代器
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
// 使用下標+for遍歷
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + " ");
}
System.out.println();
// 借助foreach遍歷
for (Integer integer : list) {
System.out.print(integer + " ");
}
System.out.println();
Iterator<Integer> it = list.listIterator();
while(it.hasNext()){
System.out.print(it.next() + " ");
}
System.out.println();
}
注意:
- ArrayList最長使用的遍歷方式是:for循環+下標 以及 foreach
- 迭代器是設計模式的一種,后序容器使用更多,在進行詳細介紹
6.ArrayList的缺陷
由于ArrayList底層是一段連續空間,當在ArrayList任意位置插入或者刪除元素時,就需要將后序元素整體往前或者往后搬移,時間復雜度為O(n),效率比較低,因此ArrayList不適合做任意位置插入和刪除比較多的場景。
為解決這個問題,java集合中又引入了LinkedList,即鏈表結構。下面一篇文章將詳細講解鏈表結構,大家可以關注一下。