java ArrayList 详解
什么是arrayList ?
简单讲就是动态数组,容量不固定无需指定数组大小;
特点:
- 既然说是动态数组,那肯定跟数组脱不了关系 底层由数组构成
- 容量不固定,有最大阈值,默认初始化为10
- 底层是数组 查询类方法效率极高(size,isEmpty,get…)
- 线程不安全
重要方法:
add:
下图中两个方法,一个是直接添加一个元素值,另一个是在指定的位置添加一个元素,操作比较简单都是调用了一个 ensureCapacityInternal方法,然后进行数组赋值,主要的步骤就是在这个方法中,其中扩容相关的都在这里边;
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
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++;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
在上述方法中会有一个判断如果容量不够了就调用 grow()方法来进行扩容,其容量是原先的1.5倍,1.8版本采用的是位运算,相当于除以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);
}
romove:
注意一点当数组进行数据删除的时候只是将元素删除,数组的长度并不会进行缩容,也就是说只有扩容没有缩容
根据位置
public E remove(int index) {
// 检查越界
rangeCheck(index);
modCount++;
// 需要移除的元素
E oldValue = elementData(index);
// 需要移动位置的元素的数量
int numMoved = size - index - 1;
// 将需要移除元素的位置后的所有元素复制到index位置开始后的numMoved个位置
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// size减1,并将之前的最后一个位置元素置空
elementData[--size] = null; // clear to let GC do its work
return oldValue;
根据值
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;
}
线程不安全
面试中我们经常会被问到arrayList 线程安全吗?答案是不安全的,
原因有下面几点:
-
扩容,当进行扩容的时候 如果有两个线程同时来进行add 操作 并且到扩容的阶段的话,会出现数组越界,就是当一个线程拿到另一个线程扩容后的size 值的时候
-
另一个是在赋值的阶段两个线程同时进行会造成数据覆盖
具体的操作可以参考一下这个:https://blog.csdn.net/u012859681/article/details/78206494
造成数据覆盖
具体的操作可以参考一下这个:https://blog.csdn.net/u012859681/article/details/78206494