list底层实现
ArrayList
Arraylist底层基于数组实现,数组的类型为Object,没有加锁,线程不安全,元素有序。
Arraylist底层默认数组初始化大小为10的object数组
Arraylist的无参构造方法
//Arraylist的构造方法
public ArrayList() {
//transient Object[] elementData;
//private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public boolean add(E e) {
//private int size;成员变量表示当前数组存放元素的个数
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;//在数组下标为0的位置添加元素
return true;
}
//ensureCapacityInternal(size + 1);方法
private void ensureCapacityInternal(int minCapacity) {
//minCapacity此时为1
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//calculateCapacity(elementData, minCapacity)方法
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//DEFAULTCAPACITY_EMPTY_ELEMENTDATA为构造方法中默认赋值的数组
//添加第一个元素时elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA成立
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);//返回DEFAULT_CAPACITY即为10
}
return minCapacity;
}
//minCapacity为10
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscIoUs code
if (minCapacity - elementData.length > 0)//elementData.length此时为0
grow(minCapacity);
}
//对elementData进行扩容
//minCapacity为10
private void grow(int minCapacity) {
// overflow-conscIoUs code
//原来的容量为0
int oldCapacity = elementData.length;
//新的容量0+0右移一位(右移一位相当于除以2)还是0
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
//将新容量赋值为10
//之后10以上的数加上10以上的数除以2后定大于10,说明这个判断是用于初始化的
newCapacity = minCapacity;
//MAX_ARRAY_SIZE为限制的最大容量
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//将数组扩容为10
//Arrays.copyOf(elementData, newCapacity);方法先开辟newCapacity长度的新数组再将elementData数组中的内容复制到新数组中
elementData = Arrays.copyOf(elementData, newCapacity);
}
此后minCapacity的值为size+1;
之后逐渐向里面添加元素,直到元素的个数超过10之后,会把原数组的大小扩容为原来的1.5倍
//添加第11个元素时候
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscIoUs code
if (minCapacity - elementData.length > 0)
grow(minCapacity);//grow(minCapacity)方法执行
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
//新的容量为原来的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
modCount++的作用:
防止多线程的情况下,A线程遍历数据,B线程在继续存放数据时产生问题。
在foreach遍历时,会检查modCount是否发生了变化,发生了变化就会抛出异常。
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
ArrayList和Vector集合的对比
相同:都是基于数组实现的,初始容量为10
不同:Vector线程安全,在添加移除等方法上都加了synchronized锁
Vector的扩容是原来的两倍,可以自定义扩容容量
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构造的构造方法
//LinkedList<Integer> list=new LinkedList<>();
//Constructs an empty list.
public LinkedList() {}//此时first=null,last=null
添加list.add(10)
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;//由于添加的是第一个元素,此时last为空,l也为空
final Node<E> newNode = new Node<>(l, e, null);//新节点pre为l,next为null,值为e
last = newNode;//让链表的尾节点指向新的节点
if (l == null)//l为空说明这是第一个节点,让头节点也指向新节点
first = newNode;
else
l.next = newNode;
size++;//链表中的元素加一
modCount++;
}
//最终的结果为
//链表上添加了一个新节点pre,next均为null。first,last均指向这个新节点
再添加节点时
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;//last此时指向刚才添加的节点
final Node<E> newNode = new Node<>(l, e, null);//新节点pre指向刚才新添的节点,next为null,值为e
last = newNode;//让链表的尾节点指向新的节点
if (l == null)
first = newNode;
else//此时l不为空
l.next = newNode;//刚才填的第一个节点指向新节点,形成双向链表
size++;//链表中的元素加一
modCount++;
}