一、ArrayList简介
- 1.1、ArrayList概述
1)ArrayList是可以动态增长和缩减的索引序列,它是基于数组实现的List类。
2)该类封装了一个动态再分配的Object[]数组,每一个类对象都有一个capacity属性,表示它们所封装的Object[]数组的长度,当向ArrayList中添加元素时,该属性值会自动增加。
3)ArrayList的用法和Vector向类似,但是Vector是一个较老的集合,具有很多缺点,不建议使用。
4)ArrayList和Collection的关系:
** 重点提示
1.如果想ArrayList中添加大量元素,可使用ensureCapacity方法一次性增加capacity,可以减少增加重分配的次数提高性能。
2.另外,ArrayList和Vector的区别是:ArrayList是线程不安全的,当多条线程访问同一个ArrayList集合时,程序需要手动保证该集合的同步性,而Vector则是线程安全的。
- 1.2、ArrayList的数据结构
1)分析一个类的时候,数据结构往往是它的灵魂所在,底层的数据结构就是数组,数组元素类型为Object类型,即可以存放所有类型数据。我们对ArrayList类的实例的所有的操作底层都是基于数组的。
2)ArrayList的数据结构是:
二、ArrayList源码分析
- 2.1、继承关系(idea 进入ArrayList类 win + alt + u)
至于为什么这么继承就不一一讲述了,自己可以去看看
- 2.2、类中的属性
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
// 版本号
private static final long serialVersionUID = 8683452581122892189L;
// 缺省容量
private static final int DEFAULT_CAPACITY = 10;
// 空对象数组
private static final Object[] EMPTY_ELEMENTDATA = {};
// 缺省空对象数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 元素数组
transient Object[] elementData;
// 实际元素大小,默认为0
private int size;
// 最大数组容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
}
- 2.3、构造方法
public ArrayList(int initialCapacity) { // 有参数构造 指定长度
// 。。。省略
}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; // 无参构造 初始化长度
}
public ArrayList(Collection<? extends E> c) {
// 。。。省略 不常用
}
- 2.4、核心方法
// 1 插入add
public boolean add(E e) {
//确定内部容量是否够了,size是数组中数据的个数,因为要添加一个元素,所以size+1,先判断size+1的这个个数数组能否放得下,就在这个方法中去判断是否数组.length是否够用了。
ensureCapacityInternal(size + 1); // 计算位置
elementData[size++] = e;//赋值给位置
return true;
}
// 2 指定位置插入
public void add(int index, E element) {
rangeCheckForAdd(index); // 检查插入位置是否合理 不合理异常IndexOutOfBoundsException
ensureCapacityInternal(size + 1); //跟上面的分析一样,具体看上面
System.arraycopy(elementData, index, elementData, index + 1, size - index); //这个方法就是用来在插入元素之后,要将index之后的元素都往后移一位,
elementData[index] = element;//在目标位置上存放元素
size++;
}
// 批量
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;
}
//指定位置批量
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;
}
- ensureCapacityInternal内部做了什么
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // 判断初始化的elementData是不是空的数组
// 如果minCapacity == 1那就没地方放,所以就将minCapacity变成10,也就是默认大小。
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureCapacityInternal(int minCapacity) { // add方法先来这里
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// if当前长度小于要添加的位置 扩容
/*
*第一种情况:由于elementData初始化时是空的数组,那么第一次add的时候,minCapacity=size+1;也就minCapacity=1,
*在上一个方法(确定内部容量ensureCapacityInternal)就会判断出是空的数组,就会给将minCapacity=10,到这一步为止,
*还没有改变elementData的大小。
*第二种情况:elementData不是空的数组了,那么在add的时候,minCapacity=size+1;
*也就是minCapacity代表着elementData中增加之后的实际数据个数,拿着它判断elementData的length是否够用,
*如果length不够用,那么肯定要扩大容量,不然增加的这个元素就会溢出。
*/
if (minCapacity - elementData.length > 0)
grow(minCapacity); //arrayList能自动扩展大小的关键方法就在这里了
}
- grow方法藏了什么东西
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length; //将扩充前的elementData大小给oldCapacity
int newCapacity = oldCapacity + (oldCapacity >> 1); //newCapacity就是1.5倍的oldCapacity
//这句话就是适应于elementData就空数组的时候,length=0,那么oldCapacity=0,newCapacity=0,
//所以这个判断成立,在这里就是真正的初始化elementData的大小了,就是为10.前面的工作都是准备工作。
if (newCapacity - minCapacity < 0){
newCapacity = minCapacity;
}
//如果newCapacity超过了最大的容量限制,就调用hugeCapacity,也就是将能给的最大值给newCapacity
if (newCapacity - MAX_ARRAY_SIZE > 0){
newCapacity = hugeCapacity(minCapacity);
}
//新的容量大小已经确定好了,就copy数组,改变容量大小咯。
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;
}
java集合 arrayList源码分析删除元素求两个list之间的交集(下)
😁 作者:Teddy (公众号:鸡仓故事汇)
ok!到这里就大功告成,小编(Teddy)在这里先感谢大家的到来。
虽然不是太详细,小编已经很努力,给小编来个一键三连(点赞,关注,收藏),小编会越来越努力。。。