LinkedList是以链表的形式存储它的数据,实现了List接口,允许null元素。LinkedList还提供额外的get,remove,insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack)、队列(queue)或双向队列(deque)。
注意:LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。
一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(…));
ArrayList使用一个内置的数组来存储元素,数组的起始容量是10。当数组需要增长时,
新容量按如下公式获得:新容量=(旧容量*3)/2+1,
新容量即为原来的1.5倍。
PS:Arraylist源码中最大的数组容量是Integer.MAX_VALUE-8,
对于空出的8位,目前解释是 :
①存储Headerwords;
②避免一些机器内存溢出,减少出错几率,所以少分配
③最大还是能支持Integer.MAX_VALUE
当Integer.MAX_VALUE-8依旧无法满足需求时)
(2)LinkedList
LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。
LinkedList中的私有内部类,定义如下:
private static class Entry {
Object element;
Entry next;
Entry previous;
}
PS:如果我们知道一个ArrayList将会有多少个元素,我们可以通过构造方法来指定容量。
当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。还可以通过trimToSize方法在ArrayList分配完毕之后去掉浪费掉的空间。
如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。
扩展:ArrayList实现RandomAccess接口,Linked并没有实现RandomAccess接口。但是RandomAccess接口里面是空的!
RandomAccess接口是一个标志接口(Marker)
List集合实现这个接口,就能支持快速随机访问
Collections类中的binarySearch()方法,源码如下:
public static <T>
int binarySearch(List<? extends Comparable<? super T>> list, T key) {
if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
return Collections.indexedBinarySearch(list, key);
else
return Collections.iteratorBinarySearch(list, key);
}
indexedBinarySerach(list,key)源码:
private static <T>
int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) {
int low = 0;
int high = list.size()-1;
while (low <= high) {
int mid = (low + high) >>> 1;
Comparable<? super T> midVal = list.get(mid);
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
iteratorBinarySerach(list,key)源码:
private static <T>
int iteratorBinarySearch(List<? extends Comparable<? super T>> list, T key)
{
int low = 0;
int high = list.size()-1;
ListIterator<? extends Comparable<? super T>> i = list.listIterator();
while (low <= high) {
int mid = (low + high) >>> 1;
Comparable<? super T> midVal = get(i, mid);
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
通过查看源代码,发现实现RandomAccess接口的List集合采用一般的for循环遍历,而未实现这接口则采用迭代器。
ArrayList用for循环遍历比iterator迭代器遍历快,LinkedList用iterator迭代器遍历比for循环遍历快,所以说,当我们在做项目时,应该考虑到List集合的不同子类采用不同的遍历方式,能够提高性能!
然而有人发出疑问了,那怎么判断出接收的List子类是ArrayList还是LinkedList呢?
这时就需要用instanceof来判断List集合子类是否实现RandomAccess接口!
要求:能够编写代码实现动态数组、明确二者时间复杂度+空间复杂度区别、清楚何时使用合适的数据结构