List接口继承了Collection接口,其主要实现类如下所示:
├List(在Collection接口的基础上新增加了一些方法)
│├LinkedList (底层是链表实现)
│├ArrayList (底层为对象数组,容量默认为10,扩容1.5,即每次增长原来的0.5倍)
│ └Vector(底层为对象数组,容量默认为10,可按规定值扩容,默认为每次增长为原来的1倍)
│ └Stack
一、List接口常用实现类介绍
1、LinkedList类底层是由双链表实现的,双链表有一个虚拟节点header,节点值为null,前驱引用指向尾节点,后继引用指向头节点。通过虚拟节点header可很方便的找到尾节点,而不用去遍历整个链表。该类具有链表的所有特性,插入、删除操作很方便,访问节点需要遍历链表(虽然删除节点也需要遍历,但不需要移动元素)较慢。
适用场景:数据的大小未知,数据动态插入与删除。
虚拟节点及其数据结构如下:
private transient Entry<E> header = new Entry<E>(null, null, null);//虚拟节点
private static class Entry<E> {
E element;
Entry<E> next;
Entry<E> previous;
Entry(E element, Entry<E> next, Entry<E> previous) {
this.element = element;
this.next = next;
this.previous = previous;
}
}
2、ArrayList类底层是由可变的对象数组实现的,对象数组默认大小为10,在容量不够时扩容为原来的1.5倍,即每次扩容大小增长0.5倍。ArrayList具有数组的所有性质,易于随机访问,一般情况下插入和删除需要移动元素(需要一定元素,扩容需要富足元素,代价较大)。
适用场景:数据大小已知,高效访问,一般不需随机插入和删除。
private transient Object[] elementData;//对象数组
//可以指定数组大小
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this(10);
}
//容量不够时做扩容处理,为原来大小的1.5倍,且需要将原来的元素复制到新的数组中,该过程较耗时。
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
3、Vector底层实现也是可变数组,其基本功能跟ArrayList类似,不同的是Vector是线程安全的,对象数组的操作全部加锁;另外其扩容大小为原来的2倍。由于加锁实现线程同步,访问效率比ArrayList慢。
适用场景:数据大小已知,高效随机访问,且需要保证线程安全。
4、Stack继承自Vector,在Vector的基础上实现了元素先入后出的操作,线程安全。
适用场景:数据大小已知,具有先入后出的特性。
二、其他知识点
1、结合排序
java.util.Collections.sort(java.util.List, java.util.Comparator)
第一个方法要求所排序的元素类必须实现java.lang.Comparable接口,该方法具有侵入性。
第二个方法要求实现一个java.util.Comparator接口。
2、集合遍历
a、for each遍历
List<Integer> list = new ArrayList<Integer>();
for (Integer j : list) {
// use j
}
b、迭代器遍历
List<Integer> list = new ArrayList<Integer>();
for (Iterator<Integer> iterator = list.iterator(); iterator.hasNext();) {
iterator.next();
}
c、下标遍历
List<Integer> list = new ArrayList<Integer>();
for (int j = 0; j < list.size(); j++) {
list.get(j);
}
一般情况下建议使用for each遍历,勿须关注下标。迭代器遍历linkedList时,get方法会从头遍历至index下标,效率较低。
3、线程安全类
Collections.synchronizedList(List<? extends E> list)类是List的线程安全的代理类,在操作list时会加锁,线程安全。
Collections.UnmodifiableList(List<? extends E> list)类是List的线程安全类,只能读,不能写。