1.数组介绍
当创建一个数组时及在内存中分配一个连续的内存,将数据顺序存入这块连续的内存中,并且只能存放相同的数据类型。
所以它的特点是寻址读取数据比较快,插入指定位置和删除比较慢。
因为是连续的空间每一个位置都有相应下标可以直接通过下标获取数据,而删除和添加需要偏移位置。
ArrayList底层就是Object数组
添加源码分析
//添加操作
public boolean add(E e) {// E 泛型传入什么类型就是什么类型
//判断是否扩容
ensureCapacityInternal(size + 1); // size初始值为0
//插入数据
elementData[size++] = e;//初始值为10
return true;
}
添加到指定位置
public void add(int index, E element) {
//验证下表是否越界
rangeCheckForAdd(index);
//验证扩容否
ensureCapacityInternal(size + 1);
// 该方法为本地方法,意思就是复制到一个新的容器中
//详情https://blog.csdn.net/m0_45230978/article/details/103899446
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
//判断是否扩容
private void ensureCapacityInternal(int minCapacity) {
/**
*elementData 表示一个Object 数组默认为null
*DEFAULTCAPACITY_EMPTY_ELEMENTDATA={}
*/
if (elementData ==DEFAULTCAPACITY_EMPTY_ELEMENTDATA ) {
//DEFAULT_CAPACITY=10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//判断是否扩容
ensureExplicitCapacity(minCapacity);
}
//判断是否扩容
private void ensureExplicitCapacity(int minCapacity) {
//修改次数
modCount++;
// 判断插入次数-容量是大于0
if (minCapacity - elementData.length > 0)
//扩容
grow(minCapacity);
}
//扩容
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//数组长度的二进制向右偏移1位
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//数组长度不可大于Integer.MAX_VALUE
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 将源数组拷贝到扩容后的数组中
elementData = Arrays.copyOf(elementData, newCapacity);
}
删除源码分析
//通过值删除
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 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; // clear to let GC do its work
return oldValue;
}
//删除
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; // clear to let GC do its work
}
//示例
ArrayList arrayList=new ArrayList();
arrayList.add("1fff");
arrayList.add("2fff");
arrayList.add("123");
arrayList.add("3fff");
arrayList.add("4fff");
//使用该方式删除会报java.util.ConcurrentModificationException错误
for (Object o : arrayList) {
if (o=="123"){
arrayList.remove(arrayList.remove(o));
}
}
//因为会触发迭代器的该方法
//该方法中在Itr类中,Itr在Arraylist中
//expectedModCount初始化时就=modCount
//当调用了remove()方法成功删除后modCount 该便所以报错
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
//可以使用迭代器的remove方法实现删除,因为该方法重新给expectedModCount赋了值
Iterator<Object> iterator=arrayList.iterator();
while (iterator.hasNext()){
if (iterator.next()=="123"){
iterator.remove();
}
}
这也是为什么插入删除慢的原因,应为他们需要重新排序。