public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
}
List的实现之一是数组的实现方式ArryList,这种实现方式也和数组一样,插入删除效率低而查询数据效率较高。首先是构造方法,可以指定初始数组的容量也可以不指定。然后创建一个Object数组。
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
这个是list的查找一个元素的方法,通过遍历ArryList元素与需要查找的元素做equals比较,如果结果为true就返回数组下标。如果查找的元素为null;则遍历查找第一个数组中为空的位置的下标。
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);
}
这是ArryList扩容的一个方法,此方法最后将elementData复制到一个新的数组中并把值赋值给elementData。新数组的长度为newCapacity。数组的复制是一种效率很低的方法,所以我们要尽量避免这种情况。方法也保证了扩容后的容量不会小于当前数组的容量也不会大于数组的最大容量。由于数组实现的list大部分的增删查改操作都和数组类似,此处就不再赘述,只说下添加元素到默认位置和指定位置
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
数组的第二种实现方式,链表的实现方式,就相反。LinkedList往列表中删除或添加元素的速度是非常快的,而获取指定元素的速度很慢,因为需要一个一个元素的遍历。LinkedList的构造方法并没有具体的实现。通常我们实用的List e=new LinkedList();构建了一个空的链表。链表的每一个元素都是一个Node
private static class Node {
E item;
Node next;
Node prev;
Node(Node prev, E element, Node next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
可以看出这是一个双向链表,每个节点Node包含了一个指向前一个节点的prev,指向下一个节点的next以及一个元素item。
我们最常使用的就是无参数的构造方法。LinkedList的无参构造方法没有具体的实现。另一个经常使用的方法是添加元素的add方法。
public boolean add(E e) {
linkLast(e);
return true;
}void linkLast(E e) {
final Node l = last;
final Node newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
void linkBefore(E e, Node succ) {
// assert succ != null;
final Node pred = succ.prev;
final Node newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
如果指定了添加节点的位置,如果位置下标是等于链表的大小就调用上面提到的向链表末尾添加节点的方法,如果不等于,则调用linkBefore方法。原理是找到要添加的节点位置的前边的节点node(index),然后通过node(index)即succ的prev找到添加位置前边的节点,然后将新添加的节点的prev指向node(index)前边的节点,将新节点的next指向node(index)。如果node(index)之前没有节点,说明新添加的节点的位置是链表的第一个位置,就将first指向新节点。如果node(index)之前存在节点,就将节点的next指向新添加的节点。