Java中的集合(二):List

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

CopyOnWriteArrayListArrayList一樣,底層仍然是一個可變大小的數組實現的,但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

VectorArrayList非常相似,底層也是一個可變長的數組,但是Vector是線程安全的,因此單純從性能尚來說,Vector的性能要低于ArrayList,但Vector類中也提供了一些,去盡可能的提升性能,優化內存存儲

/*
構造方法,使用制定的初始容量和容量增量實例化對象
*/
public Vector(int initialCapacity, int capacityIncrement)

public int capacity()//返回當前容量

public void  ensureCapacity (int minCapacity)//增加容量

public void trimToSize()//對實例的容量進行微調,使其等于實例中元素的數量

Stack

StackVector的子類,所以改類也是線程安全的。其實現了數據結構中棧,具有元素后進先出(LIFO)的規則。具有通常的push poppeek操作。

遍歷操作

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())遍歷

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容