ArrayList和LinkList源码分析
一、ArrayList
1.1 ArrayList简介
ArrayList就是动态数组,它的容量可以动态增长和缩减。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
extends AbstractList :ArrayList 继承了AbstractList类,使用其中的一些通用的方法,也可以自己实现特有的方法。
implements List<E>, RandomAccess, Cloneable, java.io.SerializableRandomAccess, Cloneable, java.io.Serializable:实现了这些接口, List, RandomAccess, Cloneable, java.io.SerializableRandomAccess, Cloneable, java.io.Serializable
1.2 主要方法
1.2.1 add()方法
add的方法有两个,传入一个参数和传入两个参数的。
-
public boolean add(E e) //直接将指定元素e追加到列表末尾
-
public void add(int index, E element) //将指定元素插入到列表中的指定位置。
ArrayList<Long> arrayList = new ArrayList();
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//初始化成一个空数组
(1)public boolean add(E e)
public boolean add(E e) {
modCount++;
//elementData初始化为空数组,size最开始默认为0
add(e, elementData, size);
return true;
}
private void add(E e, Object[] elementData, int s) {
// 判断是否需要扩容
if (s == elementData.length)
// 扩容操作 将原来的数组的长度变为数组长度的1.5倍 length + (length >> 1)
elementData = grow();
elementData[s] = e;//将元素放入到List末尾
size = s + 1;
}
private Object[] grow() {
return grow(mincapacit:size + 1);
}
//扩容,保证ArrayList至少能存储minCapacity个元素
private Object[] grow(int minCapacity) {
// 获取当前数组的容量
int oldCapacity = elementData.length;
// 扩容。新的容量=当前容量+当前容量/2.即将当前容量增加一半(当前容量增加1.5倍)。
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
//新的容量大小已经确定好了,就copy数组,改变容量大小。
//copyof(原数组,新的数组长度)
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];//DEFAULT_CAPACITY = 10;
}
}
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
// assert oldLength >= 0
// assert minGrowth > 0
int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
//传入的容量是不是小于最大容量返回传入的容量,否则返回最大容量判断
if (newLength - MAX_ARRAY_LENGTH <= 0) {
return newLength;
}
return hugeLength(oldLength, minGrowth);
}
private static int hugeLength(int oldLength, int minGrowth) {
int minLength = oldLength + minGrowth;
if (minLength < 0) { // overflow
throw new OutOfMemoryError("Required array length too large");
}
//如果传入的容量值小于等于最大容量值返回最大的Integer值2^31次方
if (minLength <= MAX_ARRAY_LENGTH) {
return MAX_ARRAY_LENGTH;
}
return Integer.MAX_VALUE;
}
(2) public void add(int index, E element) //删除指定索引处的元素:
public void add(int index, E element) {
//越界检查if (index > size || index < 0)
rangeCheckForAdd(index);
modCount++;
final int s;
Object[] elementData;
//判断数组长度与集合size是否相等
if ((s = size) == (elementData = this.elementData).length)
//相等的话扩容
elementData = grow();
//将原数组索引处(包括索引)后的元素拷贝到新数组中,放到从index+1位置开始
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
//向索引处添加元素
elementData[index] = element;
size = s + 1;
}
1.2.2 remove()方法
(1)public E remove(int index) //删除指定元素:
public E remove(int index) {
//判断传入索引是否合法
Objects.checkIndex(index, size);
final Object[] es = elementData;
//通过索引直接找到该元素
E oldValue = (E) es[index];
fastRemove(es, index);
return oldValue;
}
//专用的remove方法,跳过边界检查,并且不返回删除的值。
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
//数组大小-1,并判断i是否在数组范围内
if ((newSize = size - 1) > i)
//将索引+1到数组结尾的元素复制到索引处到数组结尾
System.arraycopy(es, i + 1, es, i, newSize - i);
//因为并未变化数组容量,所以将后面未存放的置为空
es[size = newSize] = null;
}
(2)public boolean remove(Object o)
public boolean remove(Object o) {
final Object[] es = elementData;
final int size = this.size;
int i = 0;
// 这个是很早就有的一个 java 特性,可以命名一个语句块然后通过break name的方式跳出该语句块
found: {
if (o == null) {
//遍历数组找到null元素的索引
for (; i < size; i++)
if (es[i] == null)
break found;
} else {
//遍历数组找到o元素的索引
for (; i < size; i++)
if (o.equals(es[i]))
break found;
}
return false;
}
//将索引位置删除
fastRemove(es, i);
return true;
}
1.2.3 clear()方法
public void clear() {
modCount++;
final Object[] es = elementData;
for (int to = size, i = size = 0; i < to; i++)
es[i] = null;
}
1.2.4 addAll()方法
(1)public boolean addAll(Collection<? extends E> c)
public boolean addAll(Collection<? extends E> c) {
//将集合转为数组
Object[] a = c.toArray();
modCount++;
int numNew = a.length;
if (numNew == 0)
return false;
Object[] elementData;
final int s;
if (numNew > (elementData = this.elementData).length - (s = size))
//扩容
elementData = grow(s + numNew);
System.arraycopy(a, 0, elementData, s, numNew);
//集合个数增加
size = s + numNew;
return true;
}
(2)public boolean addAll(int index, Collection<? extends E> c)
public boolean addAll(int index, Collection<? extends E> c) {
//检查索引是否合法
rangeCheckForAdd(index);
//集合转为数组
Object[] a = c.toArray();
modCount++;
int numNew = a.length;
if (numNew == 0)
return false;
Object[] elementData;
final int s;
if (numNew > (elementData = this.elementData).length - (s = size))
elementData = grow(s + numNew);
//将要复制到的索引位置到数组结尾的元素复制到当前位置+要复制的数组长度
int numMoved = s - index;
if (numMoved > 0)
System.arraycopy(elementData, index,
elementData, index + numNew,
numMoved);
//将要复制的数组复制到指定的索引处
System.arraycopy(a, 0, elementData, index, numNew);
//集合个数增加
size = s + numNew;
return true;
}
1.2.5 get()方法
public E get(int index) {
Objects.checkIndex(index, size);
return elementData(index);
}
1.2.6 contains()方法
//是否包含某个元素
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
//查找元素索引
public int indexOf(Object o) {
return indexOfRange(o, 0, size);
}
int indexOfRange(Object o, int start, int end) {
Object[] es = elementData;
//如果传入的元素是空的判断
if (o == null) {
for (int i = start; i < end; i++) {
if (es[i] == null) {
return i;
}
}
} else {
//遍历查找值相同的元素
for (int i = start; i < end; i++) {
if (o.equals(es[i])) {
return i;
}
}
}
return -1;
}
二、LinkedList
2.1 LinkedList简介
LinkedList是一个双链表,在添加和删除元素时具有比ArrayList更好的性能。但在get与set方面弱于ArrayList。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
-
extends AbstractSequentialList<E>
- AbstractSequentialList 只支持按次序访问,这也是LinkedList随机访问效率低的原因之一。
2.2 主要方法
2.2.1 add()方法
add方法有两个
-
public boolean add(E e) //将指定元素插入到链表的最后
-
public void add(int index, E element) //在指定位置添加元素
(1)public boolean add(E e)
//将指定元素插入到链表的最后
public boolean add(E e) { linkLast(e); return true; }
void linkLast(E e) {
final Node<E> l = last;
//新建节点newNode,节点的前指针指向l,后指针指向null
final Node<E> newNode = new Node<>(l, e, null);
//更新尾节点
last = newNode;
//如果原来的尾节点是null,则要更新头指针,如果不是则将原来的尾节点的后置指针指向newNode
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
(2)public void add(int index, E element)
//在指定位置添加元素
public void add(int index, E element) {
//检查索引是否合理
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
//取出对应index上的Node元素
Node<E> node(int index) {
// assert isElementIndex(index);
//"<<":*2的几次方 “>>”:/2的几次方,例如:size<<1:size*2的1次方
//if判断index<size/2
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;
}
}
//在非空节点成功之前插入元素e
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
//创建新的节点 前驱节点为succ的前驱节点,后续节点为succ,则e元素就是插入在succ之前的
final Node<E> newNode = new Node<>(pred, e, succ);
//构建双向链表,succ的前驱节点为newNode
succ.prev = newNode;
//如果前驱节点为空则first为新节点
if (pred == null)
first = newNode;
else
//构建双向链表
pred.next = newNode;
size++;
modCount++;
}
2.2.2 addAll()方法
//将集合插入到index之前
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
// 集合转数组
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred, succ;
if (index == size) {
//succ的前驱节点直接赋值为最后节点,succ赋值为null,因为index在链表最后
succ = null;
pred = last;
} else {
//取出index上的节点
succ = node(index);
pred = succ.prev;
}
//遍历插入集合
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
//将前驱节点移动到新结点上,继续循环
pred = newNode;
}
//pred已经走到最后
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
2.2.3 clear()方法
//请空链表
public void clear() { //for循环,逐条置空 for (Node<E> x = first; x != null; ) { Node<E> next = x.next; x.item = null; x.next = null; x.prev = null; x = next; } first = last = null; size = 0; modCount++; }
2.2.4 remove()方法
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
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;
//如果prev=null则删除的是头节点
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;
}
2.2.5 get()方法
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
2.2.6 set()方法
//改
public E set(int index, E element) {
//检查索引是否合法
checkElementIndex(index);
Node<E> x = node(index);
//获取指定索引节点的值
E oldVal = x.item;
//将节点元素设置为新的值
x.item = element;
return oldVal;
}
2.2.7 indexof()方法
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}

浙公网安备 33010602011771号