List
ArrayList | LinkedList | Vector | |
---|---|---|---|
线程 | 不安全 | 不安全 | 安全 |
底层实现 | 数组 | 双向链表 | 数组 |
随机访问 | 效率高 | 效率低 | 效率高 |
随机插入删除 | 效率低 | 效率高 | 效率低 |
应用场景
- 对于需要快速插入,删除元素,应该使用LinkedList。
- 对于需要快速随机访问元素,应该使用ArrayList。
- 对于“单线程环境” 或者 “多线程环境,但List仅仅只会被单个线程操作”,此时应该使用非同步的类(如ArrayList)。
- 对于“多线程环境,且List可能同时被多个线程操作”,此时,应该使用同步的类(如Vector)。
ArrayList
- 底层实现:数组
- 扩容:以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为10。添加低11个元素时,需要扩容,每次扩容为原来的1.5倍
- 线程不安全
- 遍历
//方法一,迭代器遍历
Integer value = null;
Iterator iter = list.iterator();
while (iter.hasNext()) {
value = (Integer)iter.next();
}
//方法二,随机访问,索引遍历
Integer value = null;
int size = list.size();
for (int i=0; i<size; i++) {
value = (Integer)list.get(i);
}
//方法三,for循环遍历
Integer value = null;
for (Integer integ:list) {
value = integ;
}
//使用随机访问效率最高
- 常用方法示例
import java.util.*;
/*
* @desc ArrayList常用API的测试程序
* @author skywang
* @email kuiwu-wang@163.com
*/
public class ArrayListTest {
public static void main(String[] args) {
// 创建ArrayList
ArrayList list = new ArrayList();
// 将“”
list.add("1");
list.add("2");
list.add("3");
list.add("4");
// 将下面的元素添加到第1个位置
list.add(0, "5");
// 获取第1个元素
System.out.println("the first element is: "+ list.get(0));
// 删除“3”
list.remove("3");
// 获取ArrayList的大小
System.out.println("Arraylist size=: "+ list.size());
// 判断list中是否包含"3"
System.out.println("ArrayList contains 3 is: "+ list.contains(3));
// 设置第2个元素为10
list.set(1, "10");
// 通过Iterator遍历ArrayList
for(Iterator iter = list.iterator(); iter.hasNext(); ) {
System.out.println("next is: "+ iter.next());
}
// 将ArrayList转换为数组
String[] arr = (String[])list.toArray(new String[0]);
for (String str:arr)
System.out.println("str: "+ str);
// 清空ArrayList
list.clear();
// 判断ArrayList是否为空
System.out.println("ArrayList is empty: "+ list.isEmpty());
}
}
运行结果
the first element is: 5
Arraylist size=: 4
ArrayList contains 3 is: false
next is: 5
next is: 10
next is: 2
next is: 4
str: 5
str: 10
str: 2
str: 4
ArrayList is empty: true
LinkedList
- 底层实现:双向链表
- 扩容:不存在容量不足的情况
- 线程不安全
- 遍历
//方法一,迭代器遍历
for(Iterator iter = list.iterator(); iter.hasNext();)
iter.next();
//方法二,随机访问
int size = list.size();
for (int i=0; i<size; i++) {
list.get(i);
}
//方法三,for循环遍历
for (Integer integ:list)
;
//方法四,pollFirst()来遍历
while(list.pollFirst() != null)
;
//同理的还有pollLast()、removeFirst()、removeLast()
//遍历LinkedList时,使用removeFist()或removeLast()效率最高。但用它们遍历时,会删除原始数据;若单纯只读取,而不删除,应该使用第3种遍历方式。无论如何,千万不要通过随机访问去遍历LinkedList!
- 常用方法示例
import java.util.List;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;
/*
* @desc LinkedList测试程序。
*
* @author skywang
* @email kuiwu-wang@163.com
*/
public class LinkedListTest {
public static void main(String[] args) {
// 测试LinkedList的API
testLinkedListAPIs() ;
// 将LinkedList当作 LIFO(后进先出)的堆栈
useLinkedListAsLIFO();
// 将LinkedList当作 FIFO(先进先出)的队列
useLinkedListAsFIFO();
}
/*
* 测试LinkedList中部分API
*/
private static void testLinkedListAPIs() {
String val = null;
//LinkedList llist;
//llist.offer("10");
// 新建一个LinkedList
LinkedList llist = new LinkedList();
//---- 添加操作 ----
// 依次添加1,2,3
llist.add("1");
llist.add("2");
llist.add("3");
// 将“4”添加到第一个位置
llist.add(1, "4");
System.out.println("\nTest \"addFirst(), removeFirst(), getFirst()\"");
// (01) 将“10”添加到第一个位置。 失败的话,抛出异常!
llist.addFirst("10");
System.out.println("llist:"+llist);
// (02) 将第一个元素删除。 失败的话,抛出异常!
System.out.println("llist.removeFirst():"+llist.removeFirst());
System.out.println("llist:"+llist);
// (03) 获取第一个元素。 失败的话,抛出异常!
System.out.println("llist.getFirst():"+llist.getFirst());
System.out.println("\nTest \"offerFirst(), pollFirst(), peekFirst()\"");
// (01) 将“10”添加到第一个位置。 返回true。
llist.offerFirst("10");
System.out.println("llist:"+llist);
// (02) 将第一个元素删除。 失败的话,返回null。
System.out.println("llist.pollFirst():"+llist.pollFirst());
System.out.println("llist:"+llist);
// (03) 获取第一个元素。 失败的话,返回null。
System.out.println("llist.peekFirst():"+llist.peekFirst());
System.out.println("\nTest \"addLast(), removeLast(), getLast()\"");
// (01) 将“20”添加到最后一个位置。 失败的话,抛出异常!
llist.addLast("20");
System.out.println("llist:"+llist);
// (02) 将最后一个元素删除。 失败的话,抛出异常!
System.out.println("llist.removeLast():"+llist.removeLast());
System.out.println("llist:"+llist);
// (03) 获取最后一个元素。 失败的话,抛出异常!
System.out.println("llist.getLast():"+llist.getLast());
System.out.println("\nTest \"offerLast(), pollLast(), peekLast()\"");
// (01) 将“20”添加到第一个位置。 返回true。
llist.offerLast("20");
System.out.println("llist:"+llist);
// (02) 将第一个元素删除。 失败的话,返回null。
System.out.println("llist.pollLast():"+llist.pollLast());
System.out.println("llist:"+llist);
// (03) 获取第一个元素。 失败的话,返回null。
System.out.println("llist.peekLast():"+llist.peekLast());
// 将第3个元素设置300。不建议在LinkedList中使用此操作,因为效率低!
llist.set(2, "300");
// 获取第3个元素。不建议在LinkedList中使用此操作,因为效率低!
System.out.println("\nget(3):"+llist.get(2));
// ---- toArray(T[] a) ----
// 将LinkedList转行为数组
String[] arr = (String[])llist.toArray(new String[0]);
for (String str:arr)
System.out.println("str:"+str);
// 输出大小
System.out.println("size:"+llist.size());
// 清空LinkedList
llist.clear();
// 判断LinkedList是否为空
System.out.println("isEmpty():"+llist.isEmpty()+"\n");
}
/**
* 将LinkedList当作 LIFO(后进先出)的堆栈
*/
private static void useLinkedListAsLIFO() {
System.out.println("\nuseLinkedListAsLIFO");
// 新建一个LinkedList
LinkedList stack = new LinkedList();
// 将1,2,3,4添加到堆栈中
stack.push("1");
stack.push("2");
stack.push("3");
stack.push("4");
// 打印“栈”
System.out.println("stack:"+stack);
// 删除“栈顶元素”
System.out.println("stack.pop():"+stack.pop());
// 取出“栈顶元素”
System.out.println("stack.peek():"+stack.peek());
// 打印“栈”
System.out.println("stack:"+stack);
}
/**
* 将LinkedList当作 FIFO(先进先出)的队列
*/
private static void useLinkedListAsFIFO() {
System.out.println("\nuseLinkedListAsFIFO");
// 新建一个LinkedList
LinkedList queue = new LinkedList();
// 将10,20,30,40添加到队列。每次都是插入到末尾
queue.add("10");
queue.add("20");
queue.add("30");
queue.add("40");
// 打印“队列”
System.out.println("queue:"+queue);
// 删除(队列的第一个元素)
System.out.println("queue.remove():"+queue.remove());
// 读取(队列的第一个元素)
System.out.println("queue.element():"+queue.element());
// 打印“队列”
System.out.println("queue:"+queue);
}
}
运行结果
Test "addFirst(), removeFirst(), getFirst()"
llist:[10, 1, 4, 2, 3]
llist.removeFirst():10
llist:[1, 4, 2, 3]
llist.getFirst():1
Test "offerFirst(), pollFirst(), peekFirst()"
llist:[10, 1, 4, 2, 3]
llist.pollFirst():10
llist:[1, 4, 2, 3]
llist.peekFirst():1
Test "addLast(), removeLast(), getLast()"
llist:[1, 4, 2, 3, 20]
llist.removeLast():20
llist:[1, 4, 2, 3]
llist.getLast():3
Test "offerLast(), pollLast(), peekLast()"
llist:[1, 4, 2, 3, 20]
llist.pollLast():20
llist:[1, 4, 2, 3]
llist.peekLast():3
get(3):300
str:1
str:4
str:300
str:3
size:4
isEmpty():true
useLinkedListAsLIFO
stack:[4, 3, 2, 1]
stack.pop():4
stack.peek():3
stack:[3, 2, 1]
useLinkedListAsFIFO
queue:[10, 20, 30, 40]
queue.remove():10
queue.element():20
queue:[20, 30, 40]
Vector
- 底层实现:数组
- 扩容:Vector实际上是通过一个数组去保存数据的。当我们构造Vecotr时;若使用默认构造函数,则Vector的默认容量大小是10。当Vector容量不足以容纳全部元素时,Vector的容量会增加。若容量增加系数 >0,则将容量的值增加“容量增加系数”;否则,将容量大小增加一倍。
- 线程安全 加入了synchronized关键字
- 遍历
//方法一,迭代器遍历
Integer value = null;
int size = vec.size();
for (int i=0; i<size; i++) {
value = (Integer)vec.get(i);
}
//方法二,随机访问,索引遍历
Integer value = null;
int size = vec.size();
for (int i=0; i<size; i++) {
value = (Integer)vec.get(i);
}
//方法三,for循环遍历
Integer value = null;
for (Integer integ:vec) {
value = integ;
}
//方法三,Enumeration遍历
Integer value = null;
Enumeration enu = vec.elements();
while (enu.hasMoreElements()) {
value = (Integer)enu.nextElement();
}
//使用随机访问效率最高
- 常用方法示例
import java.util.Vector;
import java.util.List;
import java.util.Iterator;
import java.util.Enumeration;
/**
* @desc Vector测试函数:遍历Vector和常用API
*
* @author skywang
*/
public class VectorTest {
public static void main(String[] args) {
// 新建Vector
Vector vec = new Vector();
// 添加元素
vec.add("1");
vec.add("2");
vec.add("3");
vec.add("4");
vec.add("5");
// 设置第一个元素为100
vec.set(0, "100");
// 将“500”插入到第3个位置
vec.add(2, "300");
System.out.println("vec:"+vec);
// (顺序查找)获取100的索引
System.out.println("vec.indexOf(100):"+vec.indexOf("100"));
// (倒序查找)获取100的索引
System.out.println("vec.lastIndexOf(100):"+vec.lastIndexOf("100"));
// 获取第一个元素
System.out.println("vec.firstElement():"+vec.firstElement());
// 获取第3个元素
System.out.println("vec.elementAt(2):"+vec.elementAt(2));
// 获取最后一个元素
System.out.println("vec.lastElement():"+vec.lastElement());
// 获取Vector的大小
System.out.println("size:"+vec.size());
// 获取Vector的总的容量
System.out.println("capacity:"+vec.capacity());
// 获取vector的“第2”到“第4”个元素
System.out.println("vec 2 to 4:"+vec.subList(1, 4));
// 通过Enumeration遍历Vector
Enumeration enu = vec.elements();
while(enu.hasMoreElements())
System.out.println("nextElement():"+enu.nextElement());
Vector retainVec = new Vector();
retainVec.add("100");
retainVec.add("300");
// 获取“vec”中包含在“retainVec中的元素”的集合
System.out.println("vec.retain():"+vec.retainAll(retainVec));
System.out.println("vec:"+vec);
// 获取vec对应的String数组
String[] arr = (String[]) vec.toArray(new String[0]);
for (String str:arr)
System.out.println("str:"+str);
// 清空Vector。clear()和removeAllElements()一样!
vec.clear();
// vec.removeAllElements();
// 判断Vector是否为空
System.out.println("vec.isEmpty():"+vec.isEmpty());
}
}
运行结果
vec:[100, 2, 300, 3, 4, 5]
vec.indexOf(100):0
vec.lastIndexOf(100):0
vec.firstElement():100
vec.elementAt(2):300
vec.lastElement():5
size:6
capacity:10
vec 2 to 4:[2, 300, 3]
nextElement():100
nextElement():2
nextElement():300
nextElement():3
nextElement():4
nextElement():5
vec.retain():true
vec:[100, 300]
str:100
str:300
vec.isEmpty():true