ArrayList类中基础方法逻辑1
主要成员变量
private static final int DEFAULT_CAPACITY = 10;//数组默认初始容量
private static final Object[] EMPTY_ELEMENTDATA = {};//定义一个空的数组实例以供其他需要用到空数组的地方调用
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//定义一个空数组,跟EMPTY_ELEMENTDATA区别就是这个空数组是用来判断ArrayList第一添加数据的时候要扩容多少。默认的构造器情况下返回这个空数组
transient Object[] elementData;//在集合中数据存储的地方,它的容量就是这个数组的长度
private int size;//当前数组的长度
一、构造方法
ArrayList构造方法有三种
无参构造:
将初始化的空的数组赋值给elementData,就是初始化一个空的集合。该方法的官方注释:Constructs an empty list
with an initial capacity of ten.(初始化一个容量为10的空列表),个人理解是在list的add()方法中初始化为10的。
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
有参构造1
入参为列表的初始化长度。
入参不能为负数,为负数报错。
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
}
}
有参构造2:
入参为一个集合;
其中elementData.getClass() != Object[].class,为什么要做如此判断,详见:https://blog.csdn.net/weixin_46122805/article/details/124756682
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
二、增删改以及各种功能性方法
在分析一部分方法的同时,会穿插着另一些功能方法
1、新增元素add()
(1)单参add()
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
我们看到第一行代码调用了ensureCapacityInternal(),这个方法是要保证存储数据的空间,以下都是扩容相关的方法,看源码:
//保证内部容量
//在这个方法中,又调用了两个方法,是扩容逻辑一系列的方法
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//计算容量
//该方法判断了当前elementData是否为空,以及为空不为空情况取得扩容数值的大小
//在这个方法中可以看到当elementData为空,第一次添加数据的时候会扩容到10,DEFAULT_CAPACITY的默认值是10
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//确定明确容量
private void ensureExplicitCapacity(int minCapacity) {
//modCount这个参数是AbstractList类中的,当集合的结构被改变,增删之类的,modCount会增加。该特性主要是防止在迭代时被修改,造成不确定性问题
modCount++;
// overflow-conscious code
//如果新增加的size大于数组的长度,就需要扩容,调用grow()
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//当集合中存储空间不足时,调用grow()方法扩容,“oldCapacity + (oldCapacity >> 1)”决定了最小扩容量为原本长度的1.5倍;"newCapacity -
MAX_ARRAY_SIZE > 0"当扩容后的长度大于ArrayList的默认最大长度时,就调用hugeCapacity()方法,该方法决定了集合的扩容最大值为
Integer.MAX_VALUE
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:
//扩容的过程是一个复制的过程,底层使用了System.arraycopy()方法,将旧数组的数据复制给新数组
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;
}
(2)多参add()
public void add(int index, E element) {
//判断index是否符合数组范围,如果大于或小于范围,报数组下标越界
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,size - index);
elementData[index] = element;
size++;
}
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
(3)单参addAll()
这个接口很好理解,这里对addAll()方法中的System.arraycopy()的参数做一个解释:
System.arraycopy(a,aindex,b,bindex,length);
将a中的数据从aindex的位置复制到b,存放的位置从bindex开始,length代表复制a中的几个元素
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
(4)多参addAll()
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
只要能够理解上边的内容,remove()\get()这些方法只要就也没问题
下一篇接着学习ArrayList的方法