List
1、ArrayList
- 數組實現。節約空間,
- 數組有容量限制,超過限制時【原始容量 * 3/2 + 1】。System.arraycopy()複製到新數組
- 最好能給出數組大小的估值。第一次插入元素時默認創建大小爲**10**的數組
- 和Vector不同,ArrayList中的操作是線程不安全的,多線程中建議Vector、CopyOnWriteArrayList
- 可以通過Collections.synchronizedList()實現線程安全
- 支持序列化,有實現java.io.Serializable接口
-
優勢
- 按數組下標訪問元素,如get(i)、set(i,e)的效率高
-
劣勢
- 按下標插入或刪除元素,如add(i,e)、remove(i),則要用System.arraycopy()來複制移動部分,效率較差。添加或刪除最後一個元素則無影響
-
用法
- 構造器
- ArrayList()
- 構造一個初始容量爲十的空列表
- ArrayList(Collection<? extends E> c)
- 構造一個包含指定集合的元素的列表,它們在集合的迭代器返回的順序中返回
- ArrayList(int initialCapacity)
- 用指定的初始容量構造一個空列表
- ArrayList()
- 常用方法
- boolean add(E e)
- void add(int index, E element)
- boolean addAll(Collection<? extends E> c)
- boolean addAll(int index, Collection<? extends E> c) 【從指定位置開始插入到該列表】
- void clear()
- Object clone() 【返回實例淺拷貝,即兩個引用指向同一實例】
- boolean contains(Object o)
- E get(int index)
- int indexOf(Object o)
- boolean isEmpty()
- int lastIndexOf(Object o) 【返回列表指定元素的最後一個索引】
- Iterator iterator
- E remove(int index)
- boolean remove(Object o)
- E set(int index, E element)
- int size();
- void sort(Comparator<? super E> c)
- Object[] toArray()
- 遍歷
- 迭代器遍歷
Integer value = null; Iterator iter = list.iterator(); while (iter.hasNext()) { value = (Integer)iter.next(); }
- for索引值遍歷
Integer value = null; int size = list.size(); for (int i=0; i<size; i++) { value = (Integer)list.get(i); }
- foreach遍歷
Integer value = null; for (Integer integ:list) { value = integ; }
- 迭代器遍歷
- 遍歷效率: for > foreach > 迭代器 ,迭代器遍歷速度最慢
- 構造器
-
Array與ArrayList
操作 Array ArrayList 創建 String[] s = new String[10] ArrayList list = ArrayList<>() 訪問 s[index] list.get(index) 更新 s[index] = “new” list.set(index, “new”) 大小 s.length list.size() 排序 java.util.Arrays.sort(array) java.util.Collections.sort(arraylist)
2、LinkedList
- 雙向鏈表實現,無容量限制
- 雙向鏈表本身佔用了更多空間,每插入一個元素都要構造一個額外Node對象和額外的鏈表指針操作
- 繼承AbstractSequentialList的雙向鏈表。可以當作堆棧、隊列、雙端隊列操作
- 實現List接口、Deque接口、Cloneable接口、Serializable接口
- LinkedList是非同步
- Entry是雙向列表結點所對應的數據結構:含有當前結點所包含的值、上一個節點、下一個節點
-
優勢
- 插入或刪除元素時,修改前後結點的指針即可,不需要複製移動,但需要部分遍歷鏈表移動到指定的位置
- 插入或刪除元素爲鏈表兩頭,如add()、addFirst()、removeLast(),可以省掉指針的移動
-
劣勢
- 按下標訪問元素,如get(i)、set(i,e),需要遍歷鏈表到指定位置,如果i>數組代銷的一半,會從末尾開始遍歷
-
用法
- 構造器
- LinkedList()
- 構造一個空列表
- LinkedList(Collection<? extends E> c)
- 構造一個包含指定集合的元素的列表,它們在集合的迭代器返回的順序中返回
- LinkedList()
- 常用方法
- boolean add(E e)
- void add(int index, E element)
- boolean addAll(Collection<? extends E> c)
- boolean addAll(int index, Collection<? extends E> c)
- void addFirst(E e) 【從此列表開始處插入指定元素】
- void addLast(E e)
- void clear()
- boolean contains(Object o)
- E get(int index)
- E getFirst()
- E getLast()
- int indexOf(Object o)
- int lastIndexOf(Object o)
- E peek() 【返回列表第一個元素,但不刪除】
- E poll() 【返回列表第一個元素,並刪除】
- E pop()
- void push(E e)
- E remove() 【返回第一個元素,並刪除】
- E remove(int index)
- boolean remove(Object o)
- int size()
- E set(int index, E element)
- Object[] toArray()
- 遍歷方法
- 迭代器遍歷
for(Iterator iterator = list.iterator(); iterator .hasNext();) iterator.next();
- 快速隨機遍歷
int size = list.size(); for (int i=0; i<size; i++) { list.get(i); }
- forearch遍歷
for (Integer temp : list);
- pollFirst()遍歷
while(list.pollFirst() != null);
- pollLast()遍歷
while(list.oillLast() != null);
- removeFirst()遍歷
try { while(list.removeFirst() != null); } catch (NoSuchElementException e) {}
- removeLast()遍歷
try { while(list.removeLast() != null); } catch (NoSuchElementException e) {}
- 迭代器遍歷
- 遍歷效率:removeFirst() 或 removeLast() 效率最高,單純讀取可用forearch遍歷,千萬不要用for隨機訪問LinkedList,效率感人
- 構造器
-
LinkedList作爲FIFO(先進先出)隊列
隊列方法 等效方法 add(e) addLast(e) offer(e) offerLast(e) remove() removeFirst() poll() pollFirst() element() getFirst() peek() peekFirst() -
LinkedList作爲LIFO(後進先出)棧
棧方法 等效方法 push(e) addFirst(e) pop(e) removeFirst(e) peek() peekFirst()
3、Vector
- 類似ArrayList,但是Vector是同步的
- vector是線程安全的,在vector的大多數方法都使用synchronized關鍵字修飾
- 當Vector的元素超過它的初始大小時,若有指定增長係數,則【原始容量+增長係數】,若沒有則翻倍
- 不支持序列化
4、Stack
- 動態數組,默認容量10
- 繼承於Vector,實現一個後進先出的堆棧
- 用法
- 常用方法
- boolean empty()
- E peek() 【查看棧頂元素,但不刪除】
- E pop()
- E push(E item)
- int search(Object o) 【返回對象在堆棧中位置】
- 常用方法
5、CopyOnWriteArrayList
- 併發優化的ArrayList
- 基於不可變對象策略,在修改時先複製出一個數組快照來修改,改好再讓內部指針指向新數組
- 因爲對快照的修改對讀操作來說不可見,所以讀讀之間、讀寫之間不互斥,寫寫之間要加鎖互斥
- 複製快照成本昂貴,適合比較典型的讀多寫少的場景
- 雖然增加addIfAbsent(e)方法,會遍歷數組來檢查元素是否存在,但性能不會太好