本篇文章主要总结了Collection接口中的三种实现类,它们各自的特性:
ArrayList 底层数据结构就是数组,随机查询速度快、增删慢,线程不安全的,效率高,允许存放重复元素
LinkedList 底层数据结构是双向链表,查询慢、增删快,线程不安全的,效率高,允许存放重复元素
Vector 底层数据结构是数组,随机查询速度快、增删慢,线程安全,效率低,允许存放重复元素
ArrayList实现类:
ArrayList 是实现了 List 接口的可扩容的数组,它的内部是基于数组实现的,相较于 Java 中的数组,容量能动态增长。
继承于AbstractList抽象类,实现了List接口,所以可以使用List中的所有方法。
ArrayList 不是线程安全的,所以在无需考虑线程安全时使用,在需要考虑线程安全的多线程环境下可以考虑使用
add方法内部实现:
ArrayList 在添加元素时,首先进行 index 范围检查,防止传入参数小于 0 或者超过数组的 size 大小,再和默认 分配的大小值进行比对,如果大于默认大小则需要进行扩容处理。扩容时首先将创建一个大小为原始数组 1.5 倍 的新数组,新数组大小不能超过 Integer 的最大值,检查完毕后进行数组元素的拷贝
public boolean add(E e){
ensureCapacityInternal(size + 1);
elementDate[size++] = e;
return true;
}
首先进行容积检查和需改次数的统计,然后存储元素,并对size+1
public void add(int index, E element) {
rangeCheckForAdd(index);
modCount++;
final int s;
Object[] elementData;
if ((s = size) == (elementData = this.elementData).length)
elementData = grow();
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
elementData[index] = element;
size = s + 1;
}
rangeCheckForAdd用于进行index的合法性检查,要求index必须是在[0,size]之间,否则会报出运行时异常。
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
ensureCapacity方法用于保证容积的正确:
public void ensureCapacity(int minCapacity) {
if (minCapacity > elementData.length
&& !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
&& minCapacity <= DEFAULT_CAPACITY)) {
modCount++;
grow(minCapacity);
}
}
如果所需要的最小容积大于数组的长度时会调用grow方法进行扩容:
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
其它方法:
remove(int index): 移除列表中指定位置的元素,并返回被删元素,删除位置后面的元素(如果有)向前移动。
size():用于获取集合中的元素个数
isEmpty():用于判断集合中的元素个数为0
contains:用于判断是否包含指定的元素
indexOf:用于在集合中查找指定元素的第一个索引序号之,如果查询不到则返回1
lastIndexOf用于在集合中从后先前查找第一个满足条件的元素下标
LinkedList实现类:
LinkedList底层的数据结构是基于双向链表的结构
内部实现:
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
transient int size = 0;//size:元素个数
transient Node<E> first;//头节点
transient Node<E> last;//尾节点
add():新增元素是向链表的末尾追加元素
remove():删除指定元素值则是从头指针开始遍历整个链表
get(int index):获取指定位置的元素
Vector实现类:
内部实现仍旧是采用数组的方式实现,但是大部分方法上都有 synchronized 同步约束,所以当前类是一个线程安全的类
add方法:
使用了synchronized同步处理,默认扩容100%
public synchronized boolean add(E e) {
modCount++;
ensureCapacity(elementCount+1)
elementData[elementCount++] = e;
return true;
}
ensureCapacity方法用于在发现当前容积不足时会调用grow方法进行扩容处理
public synchronized void ensureCapacity(int minCapacity) {
if (minCapacity > 0) {
modCount++;
if (minCapacity > elementData.length)
grow(minCapacity);
}
}
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
capacityIncrement > 0 ? capacityIncrement : oldCapacity
/* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
}
本文详细介绍了Java集合框架中ArrayList、LinkedList和Vector三种实现类的特性。ArrayList基于数组实现,查询快但增删慢,非线程安全;LinkedList采用双向链表结构,查询慢但增删快,同样非线程安全;Vector虽然也是数组实现,但它是线程安全的,但效率较低。文章深入解析了这三种数据结构的内部实现,包括添加、删除、查询等操作的细节。
342

被折叠的 条评论
为什么被折叠?



