List是有序且元素可重復集合
ArrayList
ArrayList實現了一個可變大小的數組,允許包含所有的元素,包括null。
由于ArrayList實現了List接口,所以ArrayList存儲的元素是有序,按照添加元素的先后順序進行排列。當然也可以通過Collections.sort(List<T> list);
對ArrayList內的元素進行排序,但需要注意該方法的泛型參數類型應該是Comparable類型,所以ArrayList中的元素需要實現Comparable
接口,并實現其int compareTo(T o)
方法
每一個ArrayList實例都會有一個初始容量Capacity,默認為10,你可以在構造實例時根據需要設定改容量的大小,如下:
ArrayList arrayList = new ArrayList<Integer>(20);
在插入大量數據時,為了提升性能,可以調用ArrayList
中的ensureCapacity(int minCapacity)
方法來增加ArrayList
容量,從而提高插入的效率。
需要注意的是,ArrayList
是非線程安全的,如果多個線程同時訪問同一個ArrayList
實例,并且其中至少有一個線程對ArrayList
實例進行了修改,為了保證線程安全,需要在外部實現同步。你也可以這樣創建一個同步的ArrayList
實例:
Collections.synchronizedList(new ArrayList<Integer>());
ArrayList
支持快速隨機訪問,訪問某個元素的事件復雜度是O(1).但是插入和刪除元素的操作速度很慢。
CopyOnWriteArrayList
CopyOnWriteArrayList
同ArrayList
一樣,底層仍然是一個可變大小的數組實現的,但CopyOnWriteArrayList
的不同卻在于其利用了高并發往往是讀多寫少的特性,對讀操作不加鎖,對寫操作加鎖。
源碼中,對于寫操作add(E e) | set(E e) | remove(int index)
,在進入方法后,首先加鎖,然后復制一份新的數組,對新數組進行相應操作,然后將新數組賦給舊的引用,然后再解鎖。
由于CopyOnWriteArrayList
在進行寫操作時,對容器的基本數組進行了復制,內存開銷會比較大,所以不適于存儲大數據量。
LinkedList
LinkedList
底層是一個鏈表的實現,因此在內部有許多具有鏈表特色的方法,比如:
public void addFirst(E e)//在表頭插入元素
public void addLast(E e)//在表尾插入元素
public E getFirst()//獲取鏈表的頭(第一個)元素
public E getLast()//獲取鏈表的尾(最后一個)元素
public E pop()
public E push()
...
在這里就不一一介紹了。
LinkedList
是非線程安全的,這一點同ArrayList
是一樣的,獲取同步的LinkedList
,可以這樣做:
Collections.synchronizedList(new LinkedList<Integer>());
由于LinkedList
是鏈表結構的,所以其插入操作的時間復雜度是常量級的,但是查找、刪除和更新的操作是O(n)。
Vector
Vector
和ArrayList
非常相似,底層也是一個可變長的數組,但是Vector
是線程安全的,因此單純從性能尚來說,Vector
的性能要低于ArrayList
,但Vector
類中也提供了一些,去盡可能的提升性能,優化內存存儲
/*
構造方法,使用制定的初始容量和容量增量實例化對象
*/
public Vector(int initialCapacity, int capacityIncrement)
public int capacity()//返回當前容量
public void ensureCapacity (int minCapacity)//增加容量
public void trimToSize()//對實例的容量進行微調,使其等于實例中元素的數量
Stack
Stack
是Vector
的子類,所以改類也是線程安全的。其實現了數據結構中棧,具有元素后進先出(LIFO)的規則。具有通常的push
pop
和peek
操作。
遍歷操作
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
1.foreach遍歷的方式
for(Integer i : list){
System.out.println(i);
}
2.普通for循環遍歷的方式
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
注意前兩種方式在循環內部都不能對集合的結構進行修改
3.iterator遍歷的方式
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
4.listIterator遍歷的方式
ListIterator<Integer> listIterator = list.listIterator();
while(listIterator.hasNext()){
System.out.println(listIterator.next());
}
iterator和listIterator的相同與不同
相同點:1>都可以對List集合進行遍歷。這兩個方法都是快速失敗的,也就是說除非調用迭代器內部修改集合集合的方法,否則無論在何處無論在何時修改集合都會產生快速失敗,迭代器都會拋出ConcurrentModificationException
運行時異常。
不同點:2>iterator可以用于多種集合,set、list、Map都可,而listIterator只能用于list集合
3>兩者包含的方法不同。比如,ListIterator
中有add()
方法,而Iterator
中沒有
4>ListIterator
可以實現雙向遍歷,而Iterator
只能單向向后(next()
)遍歷