前提:以ArrayList arrayList = new ArrayList<>()为例;
1.ArrayList构造器
// 1)无参构造器:底层数组没有申请空间
public ArrayList() {
// 给 ArrayList 的底层数组开辟了默认大小的空间【0个】【重点】
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
// 开辟了内存空间, 但数组长度为 0
// private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
}
// 2)构造数字: 给底层数组进行申请 initialCapacity 个空间的数组
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
// 给 elementData 申请 initialCapacit 个空间
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// initialCapacit 为 0,底层没有开辟空间,和默认初始化一样
this.elementData = EMPTY_ELEMENTDATA;
// private static final Object[] EMPTY_ELEMENTDATA = {};
} else {
// initialCapacity 小于 0,则直接抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
}
}
// 3) 构造 Collection: 只要是 Collection 下的实现类都可以被 ArrayList 构造
// ? extends E: 只要是 E 的子类及 E 类型的类都可以使用
public ArrayList(Collection<? extends E> c) {
// 把 c 转化为数组,并使 elementData 数组指向c转化后的数组
elementData = c.toArray();
// 判断 elementData 的长度是否为 0
if ((size = elementData.length) != 0) {
// 检查 c 转化后的数组是否是 Object[] 类型,不是的话全部转化为 Object[] 类型
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 数组长度为 0 的话,赋给 elementData 空数组
this.elementData = EMPTY_ELEMENTDATA;
}
}
2.打印数组元素
public String toString() {
// 迭代器
Iterator<E> it = iterator();
// 调用对象中无元素
if (! it.hasNext())
return "[]";
// 利用 StringBuilder 进行打印数组信息
StringBuilder sb = new StringBuilder();
// append 方法连接内容
sb.append('[');
// 死循环
for (;;) {
// E 是类型, e 获取当前调用对象中的值
E e = it.next();
// 若 e 和当前调用对象地址相同, 则添加字符串 this Collection, 反之,把e的内容添加到 sb 中
sb.append(e == this ? "(this Collection)" : e);
// 没有下一个元素了, 直接转化为字符串并返回
if (! it.hasNext())
return sb.append(']').toString();
// 添加逗号和空格
sb.append(',').append(' ');
}
}
// 迭代器对应方法
public abstract Iterator<E> iterator(); //对应的抽象方法
// 子类中实现父类中的抽象方法
// 注:谁调用 toString 方法, iterator 就获取谁的内容
public Iterator<E> iterator() {
// 返回迭代器对象
return new Itr();
}
3.添加元素
- add(E e):添加到ArrayList的最后
// 添加元素
public boolean add(E e) {
// 判断底层数组是否需要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
// 把元素添加到最后
elementData[size++] = e;
return true;
}
// 扩容
private void ensureCapacityInternal(int minCapacity) {
// 计算容量和确定扩容
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
// 计算容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 若 elementData 数组是默认空元素数组
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 返回 private static final int DEFAULT_CAPACITY = 10;
// 返回默认的 10 个空间的数组大小
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
// 不是默认空元素数组,直接返回 minCapacity
return minCapacity;
}
// 确定扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 若 minCapacity 比底层 elementData 数组长度大,则进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity); // 需要扩容
}
// 真正扩容的地方
private void grow(int minCapacity) {
// oldCapacity 为原数组的长度
int oldCapacity = elementData.length;
// newCapacity 为原数组长度的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// minCapacity 的值大于 newCapacity 的值,使用 newCapacity 作为数组长度
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 若 newCapacity 比 MAX_ARRAY_SIZE【Integer.MAX_VALUE - 8】还大
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 使用 Arrays.copyOf 进行扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
// 当底层数组长度比 MAX_ARRAY_SIZE【Integer.MAX_VALUE - 8】还大
private static int hugeCapacity(int minCapacity) {
// 给定的长度小于 0, 抛出异常
if (minCapacity < 0)
throw new OutOfMemoryError();//抛出异常
// 若 minCapacity 大于 MAX_ARRAY_SIZE,使用整型最大值作为数组长度
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
重点:
- 若使用无参构造器初始化底层数组的话,默认是开辟10个大下的数组空间【添加元素的时候开辟】
private static final int DEFAULT_CAPACITY = 10;- 添加元素若底层elementData数组满了,按照1.5倍进行扩容
int newCapacity = oldCapacity + (oldCapacity >> 1);- 底层的扩容是使用Arrays.copyOf方法进行扩容的
elementData = Arrays.copyOf(elementData, newCapacity);- 无参构造器中的数组赋的数组是默认空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};- 有参构造器中的数组赋值若赋为0, 那么赋的是空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
- add(int index, E element):在任意位置添加元素
// 在 index 处的位置添加元素
public void add(int index, E element) {
// 检查下标是否合法
rangeCheckForAdd(index);
// 这个地方一样的需要扩容检查,上面代码已经说明
ensureCapacityInternal(size + 1); // Increments modCount!!
// 在 elementData 数组的 index 位置拷贝到 elementData 数组的 index+1 的位置,拷贝到数组后面
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
// 插入要添加的元素
elementData[index] = element;
// elementData 数组长度自增
size++;
}
// 判断下标是否合法
private void rangeCheckForAdd(int index) {
// 若 index 比数组长度大或 index 小于 0,则抛出异常
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// System.arraycopy 方法
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
// 打印异常信息
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
4.更新元素和获取元素
- set(int index, E element):更新elementData中index处的元素值
public E set(int index, E element) {
// 判断 index 的下标是否合法
rangeCheck(index);
// 把原来的值赋给 oldValue
E oldValue = elementData(index);
// 更新 index 处的值
elementData[index] = element;
// 返回原来的值
return oldValue;
}
// 判断 index 处的合法性
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 打印异常信息
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
- get(int index):获取index处的元素
public E get(int index) {
// 判断 index 的下标是否合法
rangeCheck(index);
// 直接返回 index 处的元素值
return elementData(index);
}
// 判断 index 处的合法性
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 打印异常信息
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
5.元素的出现位置
- indexOf(Object o):元素第一次出现的位置
public int indexOf(Object o) {
// 若元素为 null
if (o == null) {
// 查找 null 第一次出现的下标【0下标开始查找】
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
// 查找元素 o 第一次出现的下标【0下标开始查找】
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
// 没有找到
return -1;
}
- lastIndexOf(Object o):元素最后一次出现的位置
public int lastIndexOf(Object o) {
// 若元素为 null
if (o == null) {
// 查找 null 元素最后一次出现的位置【从最后一个有效下标查找】
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
// 查找 o 元素最后一次出现的位置【从最后一个有效下标查找】
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
// 没有找到
return -1;
}
6.删除元素
- remove(int index):按照下标进行删除
public E remove(int index) {
// 检查下标的合法性
rangeCheck(index);
// 修改次数
modCount++;
// 保存要删除的值
E oldValue = elementData(index);
// 移动的元素个数
int numMoved = size - index - 1;
// 说明不是最后一个元素
if (numMoved > 0)
// 把 index + 1 的位置拷贝到 index 的位置
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 最后一个元素直接置为 null 即可
elementData[--size] = null; // clear to let GC do its work
// 返回删除的值
return oldValue;
}
// 判断 index 处的合法性
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 打印异常信息
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
- remove(Object o):按照元素值进行删除
public boolean remove(Object o) {
// 若元素值为 null
if (o == null) {
for (int index = 0; index < size; index++)
// 判断是否和 null 相等
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;
}
// 进行删除的地方
private void fastRemove(int index) {
modCount++;
// 移动元素个数
int numMoved = size - index - 1;
// 说明删除的不是最后一个元素
if (numMoved > 0)
// 把 index+1 - 数组长度的值 拷贝到 index - 数组长度的值【即前移】
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 删除的是最后一个元素
elementData[--size] = null; // clear to let GC do its work
}
7.查找元素是否存在、顺序表长度
- contains(Object o):查找元素是否存在顺序表中
public boolean contains(Object o) {
// 判断返回的下标是否大于 0
return indexOf(o) >= 0;
}
// 查找元素在顺序表第一次出现的位置
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
- size():顺序表的长度
public int size() {
// 直接返回顺序表长度
return size;
}
8.判断顺序表是否非空和清空顺序表
- isEmpty():判断顺序表是否为空
public boolean isEmpty() {
// 判断顺序表长度,若为 0,则为空
return size == 0;
}
- clear():清空顺序表
public void clear() {
modCount++;
// clear to let GC do its work
// 若为引用类型,则把每个引用类型置为 null
for (int i = 0; i < size; i++)
elementData[i] = null;
// 最后把顺序表长度置为0
size = 0;
}
9.ArrayList的遍历方式
- 简单for循环
public class ArrayListMethod {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
arrayList.add(5);
arrayList.add(6);
for (int i = 0; i < arrayList.size(); i++) {
System.out.print(arrayList.get(i) + " ");
}
}
}
- for - each循环
public class ArrayListMethod {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
arrayList.add(5);
arrayList.add(6);
// for - each 循环
for (Integer ret : arrayList) {
System.out.print(ret + " ");
}
}
}
- 迭代器
public class ArrayListMethod {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
arrayList.add(5);
arrayList.add(6);
// 迭代器遍历
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
Object ret = iterator.next();
System.out.print(ret + " ");
}
}
}
10.ArrayList的缺点与优点
- 添加, 删除元素效率较低
- 扩容的时候需要消耗不少空间, 若后续不使用, 造成浪费
- ArrayList可以通过下标进行随机访问和获取元素
- 顺序表适合静态的数据进行查找和更新