ArrayList概述
ArrayList是实现于List接口的集合类,其底层是基于 数组 实现的,支持随机访问。
ArrayList类的属性
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
/**
* ArrayList默认初始容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 空数组,无参构造器中创建对象用到
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 空数组,用于控制当ArrayList添加新元素时,计算扩容的容量
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
*存放集合元素
*/
transient Object[] elementData;
/**
* 集合包含的元素数量,获取集合元素数量时无需遍历,所以时间复杂度为O(1)
*/
private int size;
/**
* ArrayList所能存储元素的最大容量
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
}
ArrayList的构造方法
无参构造方法
//构造一个初始容量为 10 的空列表。
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
使用无参构造新建一个ArrayList时,当添加第一个元素时因为elementDate会等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA,所以会将集合的容量设置为默认的容量10;由此可以看出当我们用无参构造new一个ArrayList集合时,在还没有添加元素之前,集合的容量为0,只有当添加第一个元素时触发扩容,将集合的容量设置为默认容量1
带初始容量的构造方法
public ArrayList(int initialCapacity) {
//如果初始容量大于10
if (initialCapacity > 0) {
//初始化一个大小为initialCapacity的数组赋值给数组elementData
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//如果初始容量等于0
//则将前面ArrayList定义的类属性EMPTY_ELEMENTDATA空数组赋值给数组elementData
this.elementData = EMPTY_ELEMENTDATA;
} else {
//如果初始化容量小于0,则抛出IllegalArgumentException异常
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
}
}
带集合参数的构造方法
//构造一个包含指定集合的ArrayList
public ArrayList(Collection<? extends E> c) {
//利用toArray()方法将集合c转换为数组,并将转换后的数组赋值给数组a
Object[] a = c.toArray();
//如果数组中的元素个数不等于0
if ((size = a.length) != 0) {
//如果集合c的类型为ArrayList
if (c.getClass() == ArrayList.class) {
//则将集合c转化后的数组a赋值给数组elementData
elementData = a;
} else {
//否则,复制数组a并将复制后新数组赋值给elementDate数组
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
//数组中元素个数为0,则将EMPTY_ELEMENTDATA(空数组)赋值给elementDate
elementData = EMPTY_ELEMENTDATA;
}
}
ArrayList添加元素方法
ArrayList添加元素有两个方法add(E e)、add(int index,E element).
add(E e)方法
//将指定的元素添加到此集合的末尾。
public boolean add(E e) {
//确保ArrayList的容量能够容纳得下新增的元素
ensureCapacityInternal(size + 1);
//将e元素插入到elementDate数组的size位置,然后数组的长度size+1
elementData[size++] = e;
//放回true
return true;
}
add(int index,E element)方法
//在集合的指定位置插入指定元素
public void add(int index, E element) {
//检查插入的位置是否合法,如果(index > size || index < 0),则抛出IndexOutOfBoundsException异常
rangeCheckForAdd(index);
//确保ArrayList的容量能够容纳得下新增的元素
ensureCapacityInternal(size + 1);
//arraycopy方法实现依次将elemenDate数组中下标为index的元素及其以后的所有元素拷贝到下一个位置
//目的是将下标为index的位置腾出,用于存储新增的元素element
System.arraycopy(elementData, index, elementData, index + 1,size -index);
//腾出index位置,将element插入到index位置
elementData[index] = element;
//数组长度size+1
size++;
}
ArrayList添加元素过程详细解析 我们在使用ArrayList的add方法新增元素时,底层会调用
ensureCapacityInternal(int minCapacity)方法 [ 方法传入的参数minCapacity,即当前ArrayList需要的最小存储容量,值为当前数组的长度+1] 来判断ArrayList的容量是否足够;其中先通过calculateCapacity()方法计算出当前ArrayList需要的最小存储容量,接着调用ensureCapacityInternal(int minCapacity)方法中的ensureExplicitCapacity(int minCapacity)方法,用来判断当前数组是否需要进行扩容,如果当前ArrayList所需的最小存储容量大与elementData数组的长度,则调用grow(int minCapacity)方法进行扩容,在grow()方法中,首先会判断当前所需最小的存储容量是否小于0,如果小于0,则说明已经产生溢出了,否则,继续判断当前ArrayList所需的最小存储是否大于ArrayList所能存储的最大容量,如果大于则返回Integer.Max_VALUE作为新的容量,否则返回ArrayList所能存储的最大容量MAX_ARRAY_SIZE作为新的存储容量。
过程图解
图文并茂,这下你应该懂了吧! φ(>ω<*)
ArrayList的优缺点
- ArrayList的优点如下:
- ArrayList 底层以数组实现,允许对元素进行快速随机访问。ArrayList 实现了RandomAccess 接口,因此查找的时候非常快。
- ArrayList 在顺序添加一个元素的时候非常方便,非顺序添加就不合适。
- ArrayList 的缺点如下:
- 当从 ArrayList 的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
- 底层以数组实现则缺点是每个元素之间不能有间隔,当数组大小不满足时需要扩容,就要原数组中的元素复制到新的存储空间中,比较耗费性能。
多线程场景下如何使用 ArrayList
- ArrayList是非线程安全的,在多线程场景下,可以通过
Collections的synchronizedList(List<T> list)方法将其转换成线程安全的容器后再使用。如下:
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
List<Integer> securityList = Collections.synchronizedList(list);
ArrayList的常用方法
boolean add(E e)将指定的元素追加到此列表的末尾。void add(int index, E element)在此列表中的指定位置插入指定的元素。E get(int index)返回此列表中指定位置的元素。boolean contains(Object o)如果此列表包含指定的元素,则返回 true 。int indexOf(Object o)返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。boolean isEmpty()如果此列表不包含元素,则返回 true 。E set(int index, E element)用指定的元素替换此列表中指定位置的元素。int size()返回此列表中的元素数。boolean remove(Object o)从列表中删除指定元素的第一个出现(如果存在)。E remove(int index)删除该列表中指定位置的元素。boolean addAll(Collection<? extends E> c)批量将另一个集合c中的元素添加到ArrayList集合的末尾。boolean addAll(int index, Collection<? extends E> c)将另一个集合c中的所有元素插入插入到指定位置index后。void clear()从列表中删除所有元素。Iterator<E> iterator()以正确的顺序返回该列表中的元素的迭代器。int lastIndexOf(Object o)返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。ListIterator<E> listIterator()返回列表中的列表迭代器(按适当的顺序)。ListIterator<E> listIterator(int index)从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。boolean removeAll(Collection<?> c)用于删除ArrayList与另一个另一个集合c的交集部分的元素。boolean removeIf(Predicate<? super E> filter)删除满足给定谓词的此集合的所有元素。protected void removeRange(int fromIndex, int toIndex)从这个列表中删除所有索引在 fromIndex (含)和 toIndex之间的元素。void replaceAll(UnaryOperator<E> operator)将该列表的每个元素替换为将该运算符应用于该元素的结果。boolean retainAll(Collection<?> c)仅保留此列表中包含在指定集合中的元素。void sort(Comparator<? super E> c)使用提供的Comparator对此列表中的元素进行比较并排序。
ArrayList类与数组相互转换
- ArrayList类转数组
- 使用
toArray()方法返回一个包含ArrayList中所有元素的数组。
- 数组转ArrayList类
- 使用
Arrays. asList(array)进行转换。
以上就是对ArrayList的详细描述,接下来还会推出其他相关集合类的分析,欢迎大家关注留言、共同进步....
往期推荐