ArrayList源码解读
- ArrayList是一个集合,对数组进行了二次封装
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
- 先看ArrayList的默认构造函数,这里的 elementData 是ArrayList中声明的一个Objet数组
transient Object[] elementData; //声明的一个Object[] 变量
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//赋值为一个空数组
- ArrayList的指定容量初始化构造函数
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);
}
}
- ArrayList带参构造函数,可传入一个集合
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray(); // 将传入的集合转换为对象数组
if ((size = elementData.length) != 0) {//将数据元素的个数赋值给size 并且判断size不为0
// c.toArray可能不会返回一个Object[] 这是java的一个bug (bug编号:6260652)
if (elementData.getClass() != Object[].class)//再判断数据元素的类型如果不是Object[]类型
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
Hotspot 的一个bug 以下是对.toArray函数不一定返回Object[ ]的描述
为了重现这个bug,写一个案例验证
官方说明是 Arrays.asList 之后再toArray 原本应该是一个Object[ ],但返回却不一定是Object[ ]
- 数组添加元素
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 确保容量区间足够,不够要进行扩容
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//判断elementData是不是默认的
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//在传入的容量和默认容量中取最大
}
ensureExplicitCapacity(minCapacity); // 确认是否需要扩容
}
private void ensureExplicitCapacity(int minCapacity) {
//AbstractList中的变量,值为0. ArrayList初始化时 内部类Itr迭代器中expectedModCount获取了它的值
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)//如果传入的容量大于elementData的长度则进行扩容
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //数组扩容 右移1位等于除2
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);
}
LinkedList源码解读
LinkedList中有个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;
}
}
尾插法
public boolean add(E e) {
linkLast(e); //尾插法
return true;
}
void linkLast(E e) {
final Node<E> l = last; //声明l 指向最后一个节点
final Node<E> newNode = new Node<>(l, e, null); //构造上一节点为最后节点下节点为null的新节点
last = newNode;//给链表最后节点赋值为新的节点
if (l == null) //如果链表的最后节点为null 那么新节点为第一个
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
头插法
public void push(E e) {
addFirst(e);
}
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
final Node<E> f = first; //声明f 指向第一个节点
final Node<E> newNode = new Node<>(null, e, f);//构造上一节点为null下节点为最后节点的新节点
first = newNode; //使链表的第一节点为新的节点
if (f == null) // 如果链表第一节点为null 那么新节点为第一个
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
获取节点
public E get(int index) {
checkElementIndex(index); //校验节点下标是否合法
return node(index).item;
}
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) { //如果index小于 size/2 这里其实类似二分查找
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;
}
}