ArrayList源码分析
Arraylist存储内容为一个数组,在获取ArrayList的数据量时时通过获取当中变量size的,而不是数组长度。数组长度默认为10.源码如下
private transient Object[] elementData;
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
取数据量大小时:
public int size() {
return size;
}
添加元素是代码:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
看源码可知ArrayList是线程不安全的,另外size的大小也可能并不是数据量的真实大小。
ArrayList有一个方法可以调整大小为实际的数据量大小,trimToSize()方法。
LinkedList源码分析
LinkedList存储为一个链表,具体表现形式为。LinkedList存储一个开始节点和结尾节点。
transient Node<E> first;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
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++;
}
获取数据量和ArrayList一样通过获取size大小来获取
ArrayList和LinkedList区别
除了AarrayList和LinkedList存储方式不同之外,一般选择使用哪种list那使用时效率。
之前一直以为插入操作多的时候使用LinkedList而查询数据多时用ArrayList.。看源码发现并不是这一回事。
分2种情况的插入:
1:顺序插入
如果顺序插入时其实Arraylist更快一点而不是Linkedlist。原因分析:LInkedList顺序添加元素时需要改变最后一个节点元素,另外需要新建一个节点对象。而ArrayList除非数据量长度正好大于数组长度需要增加数组长度。不然的话是直接在数组的size+1的位置对象为新加元素。当然比LinkedList快
2:中间插入
ArrayList中间插入时方法:
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中间插入的方法:
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
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的中间插入方法。AyyayList的中间插入方法是先找到之前该index数值对应点node节点,然后该节点之前添加新节点,然后改变该节点之前的上一个节点对应下一个节点为新节点。示意图如下:
这里涉及到一个方法System.arrayCopy()方法,这个方法是用active修饰的。属于非java实现的底层代码。但c来写的底层无非是数组移位,而且是数组该数值之后的数据全部都要向后移动移位,这里数据量操作会非常大。因此比LinkedList慢。
使用ArrayList注意点
由于ArrayList在添加数据发现数组长度不够时会新建一个数组,会照成额外的计算。因此,当我们知道数据量时最好使用指定长度的ArrayList.。
另外ArrayList在增加数据时发现数组长度不够并不是增加固定长度的而是增加之前数组长度右位移一位的长度,也就是说新的数组长度差不多是原数组长度的2倍。
下面是array当数组长度不够时增加长度代码:
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);
}