版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ErickPang/article/details/82693734
前一篇分析了HashMap,这篇分析ArrayList的机构和常用的方法,有不对的地方也希望大咖指正。
ArrayList是一个数组,一个可以动态扩容的数组,进入正题。
构造浅析
ArrayList中有自定义属性:
- DEFAULT_CAPACITY:默认数组大小
- EMPTY_ELEMENTDATA:一个空数组
- elementData:存放数据的数组对象
- size:数组大小
ArrayList提供了3中构造,指定数组大小,无参,指定Collection集合;
//第一种指定大小的构造
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
//比较简单就是将数组按照指定的大小进行初始化
this.elementData = new Object[initialCapacity];
}
//第二种默认构造
public ArrayList() {
super();
//不指定大小则采用空数组初始化
this.elementData = EMPTY_ELEMENTDATA;
}
//第三种构造指定集合
public ArrayList(Collection<? extends E> c) {
//将指定集合转为数组
elementData = c.toArray();
//数组大小初始化
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
//若不是Object[],则转换。
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
三种构造比较简单对数据进行初始化。
set、add浅析
1、set方式,用指定的元素将指定位置的元素替换。
public E set(int index, E element) {
//判断指定位置是否越界
rangeCheck(index);
//找到对应位置的元素
E oldValue = elementData(index);
//将新元素放如指定位置
elementData[index] = element;
//返回旧值
return oldValue;
}
将新元素放到指定位置,并返回旧值。
2、add元素
public boolean add(E e) {
//保证数据容量扩容,往下看
ensureCapacityInternal(size + 1); // Increments modCount!!
//将新元素放到数组中
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
//判断数组是否为空的,若为空的则传入的大小与默认值取大作为新数组大小
if (elementData == 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);
}
private void grow(int minCapacity) {
// overflow-conscious code
//备份现有数组大小
int oldCapacity = elementData.length;
//增加当前大小的一半,oldCapacity >> 1相当于当前值右移1位,相当于除2^1
int newCapacity = oldCapacity + (oldCapacity >> 1);
//若扩容后的大小比出入的小,则采用传入的作为新的数组大小
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//若新的数组大小比默认最大值大,则取int类型的最大值
//MAX_ARRAY_SIZE =Integer.MAX_VALUE - 8
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);
}
//比较简单不做介绍
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
3、add(int index, E element)将元素放到指定位置
public void add(int index, E element) {
//判断是否越界,跟上边一样
rangeCheckForAdd(index);
//跟add(E e)中一样
ensureCapacityInternal(size + 1); // Increments modCount!!
//将所有元素按照从index位置后移1个
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//将新元素放到空出来的位置
elementData[index] = element;
size++;
}
get
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
验证是否越界,不越界直接获取指定位置元素返回。
remove浅析
数组的移动,将空余位置及其后的元素往前移动
public boolean remove(Object o) {
//若删除的元素为null,则循环整个数组看是否有空余位置,如有则删除。
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
//若不为null,则找到指定位置,然后用其后元素覆盖
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)
//将index+1位置及其后的numMoved个元素复制到index位置及其后numMoved
System.arraycopy(elementData, index+1, elementData, index,numMoved);
//数组大小减1
elementData[--size] = null; // clear to let GC do its work
}
总结
ArrayList比HashMap要简单,就是对数组的操作,以及数组拷贝。