List ,LinkedList,ArrayList,Vector
ArrayList与LinkedList(间接),Vector均直接或间接继承自AbstractList,AbstractList实现了List接口(标识接口)
Vector类:采用Object数组存储数据,默认的初始化容量为10,初始new出对象长度为本质存储的长度为10
/**
- Constructs an empty vector so that its internal data array
- has size {@code 10} and its standard capacity increment is
- zero.构造器默认为10,采用的自动扩容增长的策略为0
/
public Vector() {
this(10);
}
采用的数组扩容增长的方法
private void grow(int minCapacity) {//minCapacity统计当前的数组中存在的元素个数+1 elementCount 当minCapacity-elementData.length>0则说明需要扩容
// overflow-conscious code
int oldCapacity = elementData.length;//当前数组的长度 Object[] elementData.length
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);//capacityIncrement 开发人员可以设定增长的个数,不设定则采取当前数组的长度直接扩大二倍因为capacityIncrement默认为0
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;//新的数组容量小于当前容量
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);//检测最大容量,扩容最大集合容量为Integer.MAX_VALUE
elementData = Arrays.copyOf(elementData, newCapacity);//数组拷贝实质是底层调用System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));
}由于Vector的每个添加、删除操作均采用synchronized锁进行确保线程安全因此效率低下,被ArrayList取代,较少使用。除非特定业务需求,要求数据绝对安全。
public Vector() {
this(10);//即使调用Vector(int initCapacity)方法,类初始化仍会首先加载this关键字调用的有参方法。避免了初始化很大数组,然后不适用,浪费内存空间。
}
发现一个很"坑"的问题,自己设置了初始化数组容量的大小,但是还是默认值10.事实证明,即使采用了有参构造器,系统默认先调用this方法的代表的有参构造this首先执行
ArrayList类:仍然使用Object数组进行数据的存储,默认的初始容量大小的设置为10,但是,注意,在系统new出一个对象的时候,默认的长度是0,与Vector不同的关键点(改进之处,并不那么简单,只是线程安全不安全问题,细节上优化更多)
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/* - Shared empty array instance used for default sized empty instances. We
- distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
- first element is added.分享一个空数组的实例用来初始化,我们分辨出不同EMPTY_ELEMENTDATA,当第一个元素添加时,让数组变大,即扩容,防止创建集合不适用浪费内存,底层可能就是这莫精打细算吧
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//显而易见,刚刚初始化出来的ArrayList的长度为0,并不是10,不是一个概念
执行添加操作扩容方法:与Vector逻辑类似,扩容大小不同
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//心心念的右移位操作,速度更快1+0.5=1.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);
}
LinkedList:双链表实现
transient int size = 0;
transient Node first;//transient防止进行传输的时候序列化,没必要传输结构性数据,不关心,节省传输的体积
/**
- Pointer to last node.
- Invariant: (first == null && last == null) ||
-
(last.next == null && last.item != null)
/
transient Node last;
public LinkedList() {//普通的无参构造,无默认值
}
添加元素:
/*
- Links e as last element.
*/
void linkLast(E e) {//直接进行添加到末尾的操作
final Node l = last;
final Node newNode = new Node<>(l, e, null);//重点,将链表最后一个值传递进入构造方法,绑定成为此元素的前节点,下边的prev,设计巧妙。即再此绑定前驱节点
last = newNode;
if (l == null)//如果是首次添加的元素,直接将此节点置为第一个节点
first = newNode;
else
l.next = newNode;//已存在的最后一个元素的节点的后继节点绑定到当前添加的节点。
size++;
modCount++;
}//这个双链表厉害了
Node(Node prev, E element, Node next) {
this.item = element;
this.next = next;
this.prev = prev;
}