一,ArrayList
1,ArrayList底层数据结构
ArrayList的底层数据结构是一个数组,Object[] elementData。
以下是ArrayListde一些主要参数
// 默认数组长度 10
private static final int DEFAULT_CAPACITY = 10;
// 空实例的数组
private static final Object[] EMPTY_ELEMENTDATA = {};
// 初始化默认空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 数组 elementData
transient Object[] elementData; // non-private to simplify nested class access
// ArrayList的size 注意:不是elementData长度
private int size;
2,无参构造方法
// elementData 默认为空数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
3,有参构造方法
// 创建长度为initialCapacity的数组,
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
// initialCapacity为0则创建一个空数组
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
注意: 有参构造方法只是初始化了数组的大小,但是List的大小没有改变还是0,因为List的size()方法,获取的是list内实际元素的数量。
/**
* Returns the number of elements in this list.
*
* @return the number of elements in this list
*/
public int size() {
return size;
}
而且,此时,ArrayList提供的有关下标的方法,get(int index)或者set(int index, E element)都是会报异常的,因为这些方法里面都包含了index与size的判断,size是0的话,也就可能会报IndexOutOfBoundsException异常,
index与size的判断:checkIndex方法
Objects.checkIndex(index, size);
/**
* 关键注释
* <p>The {@code index} is defined to be out of bounds if any of the
* following inequalities is true:
* <ul>
* <li>{@code index < 0}</li>
* <li>{@code index >= length}</li>
* <li>{@code length < 0}, which is implied from the former inequalities</li>
* </ul>
*/
@ForceInline
public static
int checkIndex(int index, int length) {
return Preconditions.checkIndex(index, length, null);
}
4,add方法(扩容问题)
默认无参方法构造ArrayList,第一次add就触发扩容,数组初始长度10,之后add超出容量,数组就扩容至原来的1.5倍,扩容时新旧数组使用Arrays.copyOf(Object[] original, int newLength)
// public add方法
public boolean add(E e) {
modCount++;
// 调用private add方法
add(e, elementData, size);
return true;
}
// private add方法
private void add(E e, Object[] elementData, int s) {
// list的size 等于 elementData数组length长度时
if (s == elementData.length)
// 进行扩容grow()
elementData = grow();
elementData[s] = e;
size = s + 1;
}
// 扩容grow()方法
private Object[] grow() {
// 实际的扩容方法 size + 1
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
// 进行数组 Arrays.copyOf 将旧数组elementData 值copy到新长度数组并且返回
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
// elementData 新长度(容量)计算
private int newCapacity(int minCapacity) {
// overflow-conscious code
// 现有长度
int oldCapacity = elementData.length;
// oldCapacity >> 1 位运算 等于 oldCapacity/2 所以newCapacity = oldCapacity * 1.5
// 扩容后新长度 等与 旧长度的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
// private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 最大Integer.MAX_VALUE
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
5,remove方法
public E remove(int index) {
Objects.checkIndex(index, size);
final Object[] es = elementData;
@SuppressWarnings("unchecked") E oldValue = (E) es[index];
fastRemove(es, index);
return oldValue;
}
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
// 不是最后一个元素 执行 arraycopy
if ((newSize = size - 1) > i)
System.arraycopy(es, i + 1, es, i, newSize - i);
// 最后一个元素
es[size = newSize] = null;
}
fastRemove方法可以看出,如果remove的是list的最后一个元素,是通过数组下标置为null删除的,所以删除时删除元素时数组最后一个元素的话,效率也比较快。
6,set方法
// elementData[index] 数组下标set
public E set(int index, E element) {
Objects.checkIndex(index, size);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
7,get方法
// 直接通过下标获取数组元素 --> ArrayList查询快
public E get(int index) {
Objects.checkIndex(index, size);
return elementData(index);
}
二,LinkedList
1,LinkedList底层数据结构
LinkedList底层的数据结构是双向链表,如下图
主要参数,size以及头节点,尾节点
// size
transient int size = 0;
// 头节点
transient Node<E> first;
// 尾节点
transient Node<E> last;
// Node定义
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;
}
}
2,构造方法
// 无参构造器
public LinkedList() {
}
// 传入一个集合构造
public LinkedList(Collection<? extends E> c) {
this();
// addAll方法
addAll(c);
}
tips:addAll()方法可以详细看一下。
3,add方法(addFirst方法和addLast方法)
注意:add方法实际是尾插 linkLast
// 直接调用linkLast 尾插
public boolean add(E e) {
linkLast(e);
return true;
}
public void addFirst(E e) {
linkFirst(e);
}
public void addLast(E e) {
linkLast(e);
}
// 插入到指定index
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
// 尾插
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++;
}
// 头插入
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
// e 新节点 succ 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);
// newNode 插到succ之前
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
4,remove方法(removeFirst方法和removeLast方法)
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
// 删除头节点
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
// 删除尾节点
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
// x是否为头节点
if (prev == null) {
// x是为头节点,新的头节点为 x.next
first = next;
} else {
// x不是头节点, x.prev.next = x.next;
prev.next = next;
x.prev = null;
}
// x是否为尾节点
if (next == null) {
// x是为尾节点,重置尾节点为 x.prev
last = prev;
} else {
// x不是尾节点,x.prev.prev = x.prev
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
5,set方法
public E set(int index, E element) {
checkElementIndex(index);
// 寻找indexNode
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
// 循环寻找indexNode --> LinkedList查询慢
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;
}
}
6,get方法
public E get(int index) {
checkElementIndex(index);
// node循环查找index Node,--> LinkedList查询效率低
return node(index).item;
}
7.主要的辅助方法(linkFirst,linkLast,linkBefore,unlinkFirst,unlinkLast,unlink)
add方法提到了 linkFirst,linkLast,linkBefore
remove方法提到了 unlink,unlinkFirst,unlinkLast
三,Vector
1,Vector底层数据结构
和ArrayList一样,都是一个数组,Object[] elementData
主要参数
protected Object[] elementData;
// 当前 Vector 元素数量,Vector的size
protected int elementCount;
// elementData的Length
protected int capacityIncrement;
2,线程安全(add remove set get 方法均被synchronized关键字修饰)
基本就是ArrayList相同的方法加synchronized,所以和ArrayList很相同就不再详细过一遍了
public synchronized boolean add(E e) {
modCount++;
add(e, elementData, elementCount);
return true;
}
public synchronized E remove(int index) {
modCount++;
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
int numMoved = elementCount - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--elementCount] = null; // Let gc do its work
return oldValue;
}
public synchronized E set(int index, E element) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
3,扩容方法与ArrayList的区别
Vector数组扩容直接变成原数组的2倍长,而ArrayList是1.5倍。
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
private Object[] grow() {
return grow(elementCount + 1);
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 与ArrayList不同
// 扩容直接变成原数组的两倍长
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity <= 0) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}