1. 实现原理:
内部结构是数组。
2. 特点:
查找快,改动慢。
3. 下面以增删改查为例,进行分析
3.1 增:
介绍: 先调用ensureCapacityInternal(size +1 ),确保ArryList 容器的容量可以存下当前的值,不溢出。一下为增加操作的函数代码、
size :当前存入的个数。把要存入的数据存到最后一位。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
增加的策略:
int newCapacity = oldCapacity + (oldCapacity >> 1);
oldCapacity 向右位移一位,相当于加上原来容量/2
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);
}
带索引的增加(插入):
1. 先检查索引值是否在当前的 size (即当前存储的序列号中)
2. 确保容量
3. 增加,增加位的后一位到最后一位 存储的数据 依次向后移动一位
4. 插入到索引位置
5. size 增加
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
3.2 删除(移除):
分两种: 带索引的移除,对象的移除
索引移除:
1. 检查是否在size和0 之间,否则抛出IndexOutOfBoundsException
2. modCount++ ,用于迭代故障,只知道这些了
3. 取出要移除的元素,用于返回值
4. 计算要移动的数据个数
5. 开始移动
6. 最后一位置空
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;
}
对象移除
- 因为ArrayList 中是可以存储null 元素的, 先判断是否为空,因为可能出现下面情况
String s1 = null;
String s2 = null;
s1.equals(s2) , 直接报空指针异常了 - 循环遍历,移除指定元素。
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
}
3.3 改/查
比较简单,不做介绍
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
4. java 中复制方法的总结:
- 使用FOR循环,将数组的每个元素复制或者复制指定元素,不过效率差一点
- 使用clone方法,得到数组的值,而不是引用,不能复制指定元素,灵活性差一点
- 使用System.arraycopy(src, srcPos, dest, destPos, length)方法,推荐使用
具体代码演示:
For 循环
int[] src={1,3,5,6,7,8};
int[] dest = new int[6];
for(int i=0;i<6;i++) dest[i] = src[i];
2.使用clone
int[] src={1,3,5,6,7,8};
int[] dest;
dest=(int[]) src.clone();//使用clone创建
副本,注意clone要使用强制转换
3.使用System.arraycopy
int[] src={1,3,5,6,7,8};
int[] dest = new int[6];
System.arraycopy(src, 0, dest, 0, 6);
System提供了一个静态方法arraycopy(),我们可以使用它来实现数组之间的复制.
其函数原型是:
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
src:源数组; srcPos:源数组要复制的起始位置;
dest:目的数组; destPos:目的数组放置的起始位置;
length:复制的长度.
注意:src and dest都必须是同类型或者可以进行转换类型的数组.
有趣的是这个函数可以实现自己到自己复制,
比如:int[] fun ={0,1,2,3,4,5,6};
System.arraycopy(fun,0,fun,3,3);
则结果为:{0,1,2,0,1,2,6};