一、ArrayList
1.1简介
ArrayList是一个动态数组,它提供了动态的增加和减少元素。在使用时需要知道和注意以下几点:
- 在添加元素时,数组会随着新添加的元素逐渐增长。当元素数量达到数组容量时会带来数据向新数组里的拷贝,因此,在已知数组大小的情况下在其构造函数中指定ArrayList大小。或者在添加大量元素前,使用ensureCapacity()方法来增加数组的容量,这可以减少递增式再分配的数量。
- 数组是查询速度快,但插入、删除慢。由于元素的每一次删除或指定位置插入会导致元素后的数据前后移动一位,所以在使用时根据业务需要来选择使用数组还是链表。链表的实现原理是用每个节点的head指向下一个元素节点,这使得它在插入、删除操作时,只需要更改head指向的节点,不会牵扯到元素位置的变动,不过链表在查询上效率非常低。
1.2 类图
二、ArrayList源码分析
1.1 可变数组
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer.
*/
private transient Object[] elementData;
1.2 构造方法
//构造一个自定义容量大小的数组,数组内元素为空
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
//默认构造数组初始容量大小是10,数组内元素为空
public ArrayList() {
this(10);
}
//构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列的。
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
1.3 存储add()
public boolean add(E e) {
//添加后元素的个数是否会超出当前数组的长度,如果超出,数组将会进行扩容。
ensureCapacityInternal(size + 1);
将元素添加到数组末尾
elementData[size++] = e;
return true;
}
1.4 移除remove()
1、移除指定位置上的元素
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
return oldValue;
}
2、因为ArrayList允许数组中存在重复元素,指定移除元素时会移除此数组中首次出现的元素。
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
}
1.5 调整数据容量大小ensureCapacity()
从添加元素里面看到,每当向数组中添加元素时,都要去检查添加后元素的个数是否会超出当前数组的长度,如果超出,数组将会进行扩容,每一次扩容的大小时当前容量大小的一半,并且要将数据重拷贝到新数组中,这样子效率是非常低的。因此,我们尽可能在实际添加大量元素前使用ensureCapacity来手动增加ArrayList数组的容量,以减少递增式再分配的数量和数据的重拷贝。
public void ensureCapacity(int minCapacity) {
if (minCapacity > 0)
ensureCapacityInternal(minCapacity);
}
private void ensureCapacityInternal(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
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);
}
本博客中未标明转载的文章归作者
小毛驴所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。