ArrayList源码分析
ArrayList的类图结构
初始操作
ArrayList中定义的final常量
/**
Default initial capacity.
默认初始化容量
*/
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData; // non-private to simplify nested class access
//size:数组中实际元素个数
//length:数组在内存中开辟的地址长度
// size <= length
private int size;//默认初始化值 --> 0
空参构造器
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
有参构造器
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
}
add方法
第一次调用add()
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;//elementData[size]==e;size++;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)/*calculateCapacity(elementData, minCapacity)==10*/);
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);//10
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity/*minCapacity==10*/) {
modCount++;//java.util.AbstractList protected transient int modCount = 0;
// overflow-conscious code
if (minCapacity - elementData.length/*elementData.length==0*/ > 0)
grow(minCapacity);
}
private void grow(int minCapacity/*minCapacity==10*/) {
// overflow-conscious code
int oldCapacity = elementData.length;//oldCapacity==0
int newCapacity = oldCapacity + (oldCapacity >> 1);//newCapacity==0
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;//newCapacity==10
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);
}
第二次调用add()
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!! size + 1==2
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity/*minCapacity==2*/) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)/*calculateCapacity(elementData, minCapacity)==2*/);
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;//minCapacity==2
}
private void ensureExplicitCapacity(int minCapacity/*minCapacity==2*/) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)//2-10<0,不用扩容
grow(minCapacity);
}
第十一次调用add()
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!! size + 1==11
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity/*minCapacity==11*/) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
//calculateCapacity(elementData, minCapacity)==11
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity/*minCapacity==11*/) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)//11-10>0,扩容
grow(minCapacity);
}
private void grow(int minCapacity/*minCapacity==11*/) {
// overflow-conscious code
int oldCapacity = elementData.length;//oldCapacity==10
int newCapacity = oldCapacity + (oldCapacity >> 1);//newCapacity==10+5
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);//newCapacity==15
}
扩容机制
扩容的时候按照右移的方式进行扩容,增加数据之前的list长度值右移一位之后再加上增加数据之前的list长度值,即为扩容之后的长度
第一次扩容后长度:15
第二次扩容后长度:22
按照1.5倍的方式进行扩容(int类型自动取正数值:22,所以可以看作是1.5倍扩容)
set方法
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
get方法
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];//elementData是最开始定义的数组,按照下标的方式查找
}
remove方法
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
FailFast
快速失败机制,是java集合类应对并发访问在对集合进行迭代过程中,内部对象结构发生变化一种防护措施.这种错误检测的机制为这种有可能发生错误,通过抛出java.util.ConcurrentModificationException 通过检查modCount是否相等
LinkedList源码分析
Linked是由双向链表实现的,具有和双向链表一样的优缺点,LinkedList的类图结构
内部结构
通过一个静态内部类来实现节点
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;
}
}
LinkedList中定义的final常量
transient int size = 0;//链表最初长度:0
transient Node<E> first;
transient Node<E> last;
对LinkedList进行增加操作
push操作
push()是LinkedList中定义的方法
push方法使用头插法插入新的元素节点
linkedList1.push(5);
public void push(E e) {
addFirst(e);
}
public void addFirst(E e) {
linkFirst(e);
}
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++;
}
add操作
add()是List中定义的方法
add方法使用尾插法插入新的元素节点
第一次插入时,lastnull,所以lnull;执行first = newNode;把第一次new(final Node newNode = new Node<>(l, e, null))出来的Node节点设置为开始节点
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++;
}
get方法
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
插入方法举例
public static void main(String[] args) {
LinkedList linkedList1 = new LinkedList();
linkedList1.push(5);
linkedList1.push(4);
linkedList1.push(3);
linkedList1.push(2);
linkedList1.push(1);
linkedList1.add(6);
linkedList1.add(7);
linkedList1.add(8);
linkedList1.add(9);
linkedList1.add(10);
System.out.println(linkedList1.get(0));//结果为1
}
push是头插法,先插入的在后面;add是尾插法,先插入的在前面,
上述代码执行完毕后,链表中数据的存储顺序是1,2,3,4,5,6,7,8,9,10
按照索引从0开始取出对应的值
Vector(已经过时)
Vector和ArrayList类似,Vector中的方法是线程安全的,使用起来不灵活,效率较差,ArrayList是线程不安全的,
使用时可以用Collections工具类中的synchronizedXxx()方法转换成线程安全的,比较灵活,或者使用加锁的方式也可实现线程安全
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list) :
new SynchronizedList<>(list));
}