List
存储特点:
存储有序有索引,可重复的数据
List接口下常见的实现类:
- ArrayList
- Victor
- LinkedList
ArrayList
List接口的主要实现类 ---jdk1.2
底层结构:使用Object[] elementData存储
jdk 7情况下
ArrayList list = new ArrayList();//底层创建了长度是10的Object[]数组elementData
jdk 8情况下
ArrayList list = new ArrayList();//底层Object[] elementData初始化为{}.并没创建长度为10的数组
list.add(123);//第一次调用add()时,底层才创建了长度10的数组,并将数据123添加到elementData[0]
扩容方面jdk 7与jdk 8无异
如果此次的添加导致底层elementData数组容量不够,则扩容。
默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中。
线程不安全的,运行效率高
查询快,增删慢
源码分析
// 默认容量(并不是创建集合时的容量)
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 存放元素的数组
transient Object[] elementData;
// 实际的元素个数
private int size;
// 无参构造器
public ArrayList() {
// 没有向集合中添加元素时,容量为0
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
所以:ArrayList arrayList = new ArrayList<>();
此时的 size(实际元素个数)和 容量 都是0
add() 添加元素
arrayList.add(“番茄”);
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
// minCapacity = size + 1; 此时就是1
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 为空,第一次判断成立
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// DEFAULT_CAPACITY为10,minCapacity为1,返回最大值10
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
// 返回值为10
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
// minCapacity(10) - elementData.length(0) > 0 成立
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
// 扩容代码
// minCapacity为10
private void grow(int minCapacity) {
// overflow-conscious code
// oldCapacity = 0
int oldCapacity = elementData.length;
// newCapacity = 0
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 0 - 10 = -10 < 0 成立
if (newCapacity - minCapacity < 0)
// minCapacity赋值给newCapacity,newCapacity变为10
newCapacity = minCapacity;
// 为负数,不成立
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
// 复制指定数组(elementData为空,newCapacity为10),最后得到一个长度为10的 elementData 数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//Integer最大值-8
实例化结论:
当实例化一个ArrayList集合(空参),当没有添加元素时,容量为0;
但是当添加了第一个元素时,容量变为了10
当第二次添加元素,就会涉及到扩容问题
public boolean add(E e) {
//此时size + 1 = 11
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//minCapacity为11
private void ensureCapacityInternal(int minCapacity) {
//elementData内有数据,minCapacity为11
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//elementData不为空,判断不成立
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
//直接返回minCapacity(11)
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
//minCapacity(11) - elementData.length(10) > 0,成立
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
// minCapacity为11
private void grow(int minCapacity) {
// overflow-conscious code
// oldCapacity 被 elementData.length 赋值为10
int oldCapacity = elementData.length;
// oldCapacity >> 1相当是除以2,所以 newCapacity 为15
int newCapacity = oldCapacity + (oldCapacity >> 1);
//15 - 11 < 0 不成立
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:
//复制数组,newCapacity为15,elementData原来的容量是10,此时容量变为15
elementData = Arrays.copyOf(elementData, newCapacity);
}
扩容结论:
当再次添加了元素时,扩容为原来的1.5倍
建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity)
Victor
古老的实现类 --jdk1.0
底层结构:使用Object[] elementData存储
jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组。
在扩容方面,默认扩容为原来的数组长度的2倍。
线程安全的,运行效率低
LinkedList
底层结构:使用双向链表存储
LinkedList list = new LinkedList(); 内部声明了Node类型的first和last属性,默认值为null
list.add(123);//将123封装到Node中,创建了Node对象。
Node的定义:体现了LinkedList的双向链表
查询慢,增删快
源码分析
transient int size = 0;
//指向第一个元素的指针
transient Node<E> first;
//指向最后一个元素的指针
transient Node<E> last;
public LinkedList() {
}
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++;
}
private static class Node<E> {
//item 当前元素,实际的数据
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;
}
}
第一次add
第二次add