List集合實現類之ArrayList、Vector和LinkedList

List集合的實現類有3種,分別是ArrayList、Vector和LinkedList,下面我將對這3個實現類的區別進行詳細講解。

1)ArrayList
ArrayList繼承自AbstractList而實現了List,它是最常用的List實現類,內部是通過數組實現的,所以插入或者刪除元素時,需要對數組進行復制、移動、代價比較高,因此,它適合隨機查找和遍歷,不適合插入和刪除。

public class ArrayListTest {
	public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer>();
		list.add(5);
		list.add(6);
		list.add(7);
		list.add(8);
		list.add(9);
		list.add(10);
		
		// 通過迭代器遍歷
		Iterator<Integer> iterator = list.iterator();
		while (iterator.hasNext()) {
			System.out.print(iterator.next() + " ");
		}
		System.out.println("\n--------------------------");
		
		// for循環遍歷
		for (Integer integer : list) {
			System.out.print(integer + " ");
		}
		System.out.println("\n--------------------------");
		
		// 隨機訪問,通過list.get(i)獲得索引值去遍歷。
		for (int i = 0; i < list.size(); i++) {
			System.out.print(list.get(i) + " ");
		}
	}
}

ArrayList之所以線程不安全,從其add()方法就可以看出:

public boolean add(E e) {
	ensureCapacityInternal(size + 1);  //確保容量是否充足
	elementData[size++] = e;           //將元素添加至數組
	return true;
}

從底層源碼可以看出,add()添加元素的時候是分兩步走的:

(1)elementData[size] = e;           

(2)size++;

     假設有兩個線程,線程 A 先將元素存放在位置 0。但是此時 CPU 調度線程A暫停(線程A僅僅完成了步驟1,Size沒有自增),線程 B 得到運行的機會。線程B也向此 ArrayList 添加元素,此時 Size 仍然等於 0 ,所以線程B也將元素存放在位置0。然後線程A和線程B都繼續運行,都增加 Size 的值。 那好,現在我們來看看 ArrayList 的情況,元素實際上只有一個,存放在位置 0,而 Size 卻等於 2。這就是“線程不安全”了。 

2)LinkedList
LinkedList底層採用鏈表結構進行數據存儲,很適合數據的動態插入和刪除(add()和remove()方法),隨機訪問和遍歷速度比較慢。需要注意的是:LinkedList提供了List接口中未定義的方法,專門用於操作表頭和表尾元素,所以可以當作堆棧、隊列和雙向隊列使用。

public class LinkedListTest {
	public static void main(String[] args) {
		List<Integer> list = new LinkedList<Integer>();
		list.add(5);
		list.add(6);
		list.add(7);
		list.add(8);
		list.add(9);
		list.add(10);

		// 通過迭代器遍歷
		Iterator<Integer> iterator = list.iterator();
		while (iterator.hasNext()) {
			System.out.print(iterator.next() + " ");
		}
		System.out.println("\n--------------------------");
		
		// for循環遍歷
		for (Integer integer : list) {
			System.out.print(integer + " ");
		}
		System.out.println("\n--------------------------");
		
		// 隨機訪問,通過list.get(i)獲得索引值去遍歷,不建議
		for (int i = 0; i < list.size(); i++) {
			System.out.print(list.get(i) + " ");
		}

	}
}

3)Vector
Vector底層也是通過數組實現的,不同的是它支持線程的同步,即某一時刻只有一個線程能夠寫Vector,避免多線程同時寫而引起的不一致性,但實現同步需要很高的花費,因此,訪問它比訪問ArrayList慢。


public class VectorTest {
	public static void main(String[] args) {
		Vector<Integer> vec = new Vector<Integer>();
		vec.add(5);
		vec.add(6);
		vec.add(7);
		vec.add(8);
		vec.add(9);
		vec.add(10);

		// 通過迭代器遍歷
		Integer value = null;
		for (int i = 0; i < vec.size(); i++) {
			value = (Integer) vec.get(i);
			System.out.println(value + " ");
		}
		System.out.println("\n--------------------------");

		// for循環遍歷
		Integer value2 = null;
		for (Integer integ : vec) {
			value2 = integ;
			System.out.println(value2 + " ");
		}
		System.out.println("\n--------------------------");

		// 隨機訪問,通過索引值去遍歷(Vector實現了RandomAccess接口,支持通過索引值去隨機訪問元素)
		Integer value3 = null;
		for (int i = 0; i < vec.size(); i++) {
			value3 = (Integer) vec.get(i);
			System.out.println(value3 + " ");
		}
		System.out.println("\n--------------------------");

		// Enumeration遍歷
		Integer value4 = null;
		Enumeration enu = vec.elements();
		while (enu.hasMoreElements()) {
			value4 = (Integer) enu.nextElement();
			System.out.println(value4 + " ");
		}

	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章