目录
ArrayList 继承了 AbstractList ,并实现了 List 接口。
1方法
ArrayList 常用方法列表如下:
方法 | 描述 |
---|---|
add() | 将元素插入到指定位置的 arraylist 中 |
addAll() | 添加集合中的所有元素到 arraylist 中 |
clear() | 删除 arraylist 中的所有元素 |
clone() | 复制一份 arraylist |
contains() | 判断元素是否在 arraylist |
get() | 通过索引值获取 arraylist 中的元素 |
indexOf() | 返回 arraylist 中元素的索引值 |
removeAll() | 删除存在于指定集合中的 arraylist 里的所有元素 |
remove() | 删除 arraylist 里的单个元素 |
size() | 返回 arraylist 里元素数量 |
isEmpty() | 判断 arraylist 是否为空 |
subList() | 截取部分 arraylist 的元素 |
set() | 替换 arraylist 中指定索引的元素 |
sort() | 对 arraylist 元素进行排序 |
toArray() | 将 arraylist 转换为数组 |
toString() | 将 arraylist 转换为字符串 |
ensureCapacity() | 设置指定容量大小的 arraylist |
lastIndexOf() | 返回指定元素在 arraylist 中最后一次出现的位置 |
retainAll() | 保留 arraylist 中在指定集合中也存在的那些元素 |
containsAll() | 查看 arraylist 是否包含指定集合中的所有元素 |
trimToSize() | 将 arraylist 中的容量调整为数组中的元素个数 |
removeRange() | 删除 arraylist 中指定索引之间存在的元素 |
replaceAll() | 将给定的操作内容替换掉数组中每一个元素 |
removeIf() | 删除所有满足特定条件的 arraylist 元素 |
forEach() | 遍历 arraylist 中每一个元素并执行特定操作 |
2源码实现
2.1继承关系
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList继承自AbstractList (AbstractList类是抽象类实现自List接口,对接口中通用的方法做了实现,子类可以不用实现,子类如果有特殊需求可以重写对应方法)
ArrayList实现接口List、RandomAccess、Cloneable、Serializable
(List接口 是ArrayList、Linkedlist的接口,定义了集合中大部分方法;
RandomAccess接口 表明当前类可以随机访问;
Cloneable接口 表明当前类是可以被克隆;
Serializable接口 表明当前类是可以支持序列化和反序列化)
2.2构造函数
//通过 初始容量initialCapacity参数 来实例化ArrayList
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;
}
//通过 集合实例 来实例化ArrayList
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
//完成数据拷贝
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
2.3属性信息
//存储元素位置
private transient Object[] elementData;
//存储元素个数
private int size;
//父类提供的属性 记录集合数据变更版本值(新增、修改、删除) ,和业务无关
private int modcount 修改版本号
2.4默认值或默认属性
//默认的数组初始容量
private static final int DEFAULT_CAPACITY = 10;
//空数组实例
private static final Object[] EMPTY_ELEMENTDATA = {};
2.5底层数据结构
底层数据结构是:数组
2.6扩容机制
//扩容大小
int newCapacity = oldCapacity + (oldCapacity >> 1);
//arraylist集合扩容时按照1.5倍进行扩容
2.7常用方法研究
2.7.1add()
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
//将新增元素插入elementData数组中
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++;
//数据空间不足,考虑扩容
if (minCapacity > elementData.length )
grow(minCapacity);
}
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
add过程:
1、如果存储数组为空,获取默认的大小值是10
2、如果需要大小超过数组大小、考虑扩容,按照原数组大小的1.5倍扩容
3、通过创建新数组,将元素组大小拷贝到新数组中
4、将新增元素插入最后的size位置并对size进行加1操作
public void add(int index, E element) 添加数据;在指定位置添加数据,需要保证index合法,并将index之后的数据后移以为,然后插入新值
2.7.2get(int index)
public E get(int index) {
//检查下标的合法性 0<= index <size
rangeCheck(index);
//通过下标指定位置来获取数据
return elementData(index);
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
2.7.3remove(Object o) 删除
remove(int index) 删除
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;
}
//将index后续的数据前移一位
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
ArrayList和数组区别?
1、ArrayList底层封装数组,提供了丰富API操作
2、存储数据:ArrayList存储的是自定义对象,基本包装类型,不能存储基本类型,即使我们可以向里面put一个基本数据类型,那么也是基于自动装箱特性,将基本数据类型转换成对象; 数组可以存放自定义类型,包装类型、基类类型(int)
基本类型对应的包装类表如下:
基本类型 | 引用类型 |
---|---|
boolean | Boolean |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
此外,BigInteger、BigDecimal 用于高精度的运算,BigInteger 支持任意精度的整数,也是引用类型,但它们没有相对应的基本类型。
3、ArrayList是可以自动扩容的 ,数组不能自动扩容
3特点总结
①插入有序
②数据可以重复
③可以存储null值
④底层数据结构是数组
⑤可以动态扩容
⑥线程不安全