ArrayList是我们经常使用的集合类。底层是通过数组实现的!
先看一下实现原理图
由图可知,ArrauyList是按顺序存储数据的。
public class ArrayList
implements List
size:集合中存储数据的数目。
elementData:这个就是集合底层使用的数组了。
1
public ArrayList(int initialCapacity) {
super();
/*容量肯定不能小于0*/
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
2
public ArrayList() {
this(10);
}
3
public ArrayList(Collection c) {
/*转成数组*/
elementData = c.toArray();
/*看看数组的长度*/
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
/*c.toArray()可能不会返回Object[],如果类型不对,需要转化。*/
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
modCount++;//更改次数+1
// overflow-conscious code
/*当前需要的容量 - 底层数组的容量 > 0 说明底层数组长度不够用啦,要扩容 */
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;
/*如果扩容后的容量大于限制的最大容量,调用方法判断minCapacity是否大于ArrayList允许分配的最大容量*/
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);
}
/*需要的容量是否大于MAX_ARRAY_SIZE,是的话直接将需要的容量设置为Inteer的最大容量,不是就直接设置为MAX_ARRAY_SIZE*/
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
add()方法主要关注扩容问题!
如果此时集合的容量已经是最大容量且存满了数据,即Integer的MAX_VALUE,通过扩容时发现MAX_VALUE不会再扩大。在add()方法中,给elementData[size++] = e;就会发现size=MAX_VALUE,size+1>MAX_VALUE,底层数组中并没有MAX_VALUE+1这个index,所以会报数组越界,所以ArrayList集合的容量是有上限的!
public E get(int index) {
/*检查index是否大于ArrayList存储数据数量*/
rangeCheck(index);
/*直接去数组对应小标找到这个值,直接返回*/
return elementData(index);
}
逻辑相当简单,只要判断index是否超出集合此时集合拥有值的数量。超出就报异常。
remove(int index)
public E remove(int index) {
//检查index是否合法
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
/*需要移动元素的数目*/
int numMoved = size - index - 1;
if (numMoved > 0)
/*在该方法里实现数据的移动*/
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
/*将无用结点设置为null*/
elementData[--size] = null; // Let gc do its work
/*返回删除的值*/
return oldValue;
}
remove(Object o)
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
}
这里要注意的是,若存此时集合存在多个object.equals(true),那么只会讲匹配的第一次对象移除。
所有的移除数据后的数据都要往前移动一个。如图