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 + " ");
}
}
}