list集合作为一个有序的集合,能够使用户很好的掌握元素在列表中的位置,通过整数的索引就可以从列表中获取想要的数据。
1.Collection
collection类是集合中就基本的接口,一个集合代表这一组对象,有些集合是有序的有些是无序的,jdk没有提供任何来自Collection接口的直接实现,它提供的是更多的子接口的实现例如list和set,所以这个接口是为了保证集合最大的通用性为目的设置的,他的方法名主要有:
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray(); //返回数组
boolean add(E e);
boolean remove(Object o);
2.ArrayList
是一个可调整大小的数组,继承List(Collection子接口)接口,实现了大部分的list操作,可插入所有类型元素以及重复值,包括null值。除了基本操作之外,还提供了很多控制内部数组大小的方法,非线程同步。类继承如下:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
transient Object[] elementData; //存放元素的Object数组
...
}
add方法
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 完成扩容功能
elementData[size++] = e;
return true;
}
我们主要分析扩容方法:
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //如果表为第一次创建,则初始化容器长度
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //记录操作
// 如果最小容量大于容器长度则需要对数组进行扩充
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //扩充1/2
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0) //如果扩充超过最大可扩充长度(最大为int的最大值)则重新取值
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity); //创建一个新的数组
}
remove方法
public boolean remove(Object o) {
if (o == null) { //如果存的是空值
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) { //调用equals判断是否相等
fastRemove(index);
return true;
}
}
return false;
}
/*
* Private remove method that skips bounds checking and does not
* return the value removed.
*/
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1; //需要移动的元素数量
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved); //调用arraycopy覆盖需要删除的值
elementData[--size] = null; // clear to let GC do its work
}
get 方法
public E get(int index) {
rangeCheck(index); //判断index是否超出范围
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index]; //通过下标获取元素
}
根据源码可知添加操作比删除操作在时间复杂度上更小,添加是O(1),删除是O(n),容器的扩容和删除元素是调用copyof和arrycopy方法的,底层实现的是c++,所以效率会更高。容器的容积是有限的,最大值为int类型的最大值。
2.LinkList
属于双链表结构,继承List和Deque接口,允许插入任何值以及重复值,包括空值。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
transient int size = 0; //容量
transient Node<E> first; //链表第一个元素
transient Node<E> last; //链表最后一个元素
private static class Node<E> {
E item;
Node<E> next; //下一个元素
Node<E> prev; //上一个元素
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
....
}
Deque:定义了双链表的操作方法,提高子类的通用性
AbstractSequentialList:此抽象类提供了框架的实现以减小实现此接口的工作量,适用于顺序存储列表的实现。
add方法
public boolean add(E e) {
linkLast(e); //插入尾部连接
return true;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null) //如果第一次插入
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
remove方法
public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
E unlink(Node<E> x) { //x需要删除的元素
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) { //如果删除的是第一个元素
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) { //如果删除的是最后一个元素
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null; //交给垃圾回收器
size--;
modCount++;
return element;
}
get方法
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) { //判断index是否是数组长度的前段
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;
}
}
linklist类,内部是一个双向链表结构。链表内的每个node对象保存了前后元素的引用。我们可以向链表两端进行插入删除的操作,除此之外他不会受到容量的限制,数组元素可以有无限多个(与虚拟机配置有关);查询方面需要通过从头或者尾开始遍历相对线性表来说效率会低些。
3.Vector
同步版本的ArrayList类,与ArrayList实现原理相差无几。唯一区别就是Vector是线程安全的。主要的add方法如下:
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1); //确保容器容量足够
elementData[elementCount++] = e;
return true;
}
以上就是我对list集合的理解。