List体系如下:
类与接口说明:
1、Collection:高度抽象出来的集合、定义某一类集合所具有的基本的方法、标准。
2、Iterable:标识性接口、要求子类提供获取Iterator方法、并且要实现Iterator具有的几个方法。
3、Iterator:迭代器、用于迭代Collection中元素、要求子类必须实现获取Iterator的方法。
4、List:以队列的形式存储、操作元素、定义了这种形式的集合所具有的基本方法、以及方法的定义。要求List实现类集合中每个元素都有索引、索引值从0开始。
5、AbstractCollection:Collection的实现类、要求需要实现Collection接口的类都必须从它继承、目的是用于简化编程。
6、AbstractList:继承AbstractCollection、实现List接口中定义方法、目的也是简化编程、并且其内部提供了获取Iterator、ListIterator的方法。
7、AbstractSequencedList:继承AbstractList、使得List支持有序队列、比如链表形式存储操作元素。
8、ArrayList:继承AbstractList、以动态数组的形式存储、操作元素。
9、LinkedList:继承AbstractSequencedList、实现Deque、List接口、以双向链表的形式存储、操作元素。
10、Vector:继承AbstractList、以动态数组的形式存储、操作元素、线程安全。
ArrayList 与 LinkedList对比:
相同点:
1)都直接或者间接继承了AbstractList,所以都支持以索引的方式操作元素;
注:ArrayList初始化容量为10,扩容代码如下:)
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
3)都是线程不安全的、一般用于单线程的环境下、要想在并发的环境下使用可以使用Collections工具类包装。
不同点:
1)ArrayList是通过动态数据保存数据的,LinkedList是通过双向链表保存数据的;
2)相对与ArrayList而言,LinkedList继承了AbstractSequentialList,而AbstractSequentialList继承了AbstractList,所以使得LinkedList不仅保留了以索引操作元素的功能,同时实现了双向链表所具有的功能;
3)对集合中元素进行不同的操作效率不同、LinkedList善于删除、添加元素、ArrayList善于查找元素。本质就是不同数据结构之间差异。
ArrayList 与 Vector的对比:
相同点:
1)都是继承AbstractList、拥有相同的方法的定义;
2)内部都是以动态数组来存储、操作元素的、并且都可以自动扩容。
不同点:
1)线程安全:ArrayList是线程不安全的、适用于单线程的环境下、Vector是线程安全的、使用与多线程的环境下;
2)构造方法:Vector有四个构造方法、比ArrayList多一个可以指定每次扩容多少的构造方法;
3)扩容问题:每当动态数组元素达到上线时、ArrayList扩容为1.5倍,Vector为2倍;Vector扩容代码如下:
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
4)效率问题:因为Vector要同步方法、这个是要消耗资源的、所以效率会比较低下;
数组、ArrayList、LinkedList、Vector操作元素对比:
| 实现机制 | 查询 | 写 | 迭代操作 |
数组 | 连续内存区域保存元素数据 | 1 | 不支持 | 不支持 |
ArrayList | 以数组保存数据 | 2 | 2 | 2 |
LinkedList | 以链表保存数据 | 4 | 1 | 1 |
Vector | 以数组保存数据 | 3 | 3 | 3 |
数组牺牲长度变化,直接在内存在开辟固定空间保存数据,所以查询速率最快,但是因为size大小固定,所以不支持写操作。
a)ArrayList查询的速率比LinkedList的快,两者都是通过索引去查找元素,ArrayList是直接通过index定位到元素位置,而LinkedList是通过二分法确定元素位置范围,再逐个查找,直到找到该元素为止。相比ArrayList 来说LinkedList更耗时,更耗费资源。两者查询元素源码如下:
/**
*ArrayList通过索引查询元素
**/
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}
/**
*LinkedList通过索引查询元素
**/
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
但是ArrayList的写操作效率明显低于LinkedList,原因如下:
对于指定index处的插入、删除、ArrayList和LinkedList都是先通过索引查找到指定位置、然后进行下一步的插入删除操作、上面我们知道LinkedList是先通过二分法查找index范围再确定index具体位置、但是ArrayList是直接定位到index处、为什么LinkedList反而快?依然通过源码找原因。
对比上面代码可以看出来ArrayList每当插入一个元素时、都会调用System.arraycopy()将指定位置后面的所有元素后移一位、重新构造一个数组、这是比较消耗资源的、而LinkedList是直接改变index前后元素的上一个节点和下一个节点的引用、而不需要动其他的东西、所以效率很高。
ArrayList、Vector都是继承与AbstractList、并且在类结构上没有多少差异、但是因为Vector要同步方法、所以在性能上不如ArrayList、从源码也可以看出Vector许多方法都是使用关键字synchronized修饰的。