1)ArrayList 特点
List 接口的可变数组实现,ArrayList 允许使用任何元素,包括 null。
ArrayList 和 Vector 基本类似,只不过 Vector 是线程安全的,ArrayList 是线程不安全的。
size、isEmpty、get、set、iterator 和 listIterator 以常量时间运行,其他的操作基本以线性时间运行。
每个 ArrayList 都有一个容量,容量表示该 ArrayList 当前能容纳的元素个数,随着元素的增加,ArrayList 会自动扩容。
在创建 ArrayList 时可以指定一个合适的初始化容量,以减少频繁扩容带来的性能损耗。
ArrayList 是线程不安全的,多线程并发访问 ArrayList 并且至少有一个线程修改了它的结构【增加、删除元素、扩容等】,
则 ArrayList 将抛出 ConcurrentModificationException 异常。快速失败机制:iterator 和 listIterator 返回的迭代器是快速失败的,如果不是通过 ListIterator#remove() 或 ListIterator#add(Object) 方法修改其结构,
则 ArrayList 将尽最大努力抛出 ConcurrentModificationException 异常。ArrayList 的缩容机制:通过 trimToSize 方法将 ArrayList 的容量缩小为当前元素的个数,以减少 ArrayList 的内存占用。
ArrayList 的扩容机制:默认为 1.5 倍向下取整扩容,如果批量添加元素,则以 size+newNum 进行扩容。
2)创建实例
/** * ArrayList 底层存储元素的数组缓冲区 */ transient Object[] elementData; // 用于在空实例之间共享的空对象数组,用于简化扩容实现 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 创建容量为 10 的空 ArrayList 实例 public ArrayList() { this.elementData = ArrayList.DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /** * 基于用户指定的容量创建空 ArrayList 实例 */ public ArrayList(int initialCapacity) { if (initialCapacity > 0) { // 创建指定大小的对象数组 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { // 使用共享的空数组 this.elementData = ArrayList.EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } /** * 基于指定的集合创建 ArrayList 实例 */ public ArrayList(Collection<? extends E> c) { // 集合转化为对象数组 this.elementData = c.toArray(); /** * 集合容量不为 0,并且类型不是 Object[].class,则将其转换为对象数组。 */ if ((this.size = this.elementData.length) != 0) { if (this.elementData.getClass() != Object[].class) { this.elementData = Arrays.copyOf(this.elementData, this.size, Object[].class); } } else { // 空集合默认使用共享空数组 this.elementData = ArrayList.EMPTY_ELEMENTDATA; } }
3)在尾部添加元素
/** * 【modCount 属性定义在 AbstractList 中】 * 【ArrayList 被结构化修改的次数,结构化修改主要是改变 List 大小的操作】 * 【该属性主要被 {@code iterator} and {@code listIterator} 方法返回的迭代器使用, * 用于在迭代器遍历元素时阻止并发修改带来的数据错误,如果此字段的值发生意外的更改, * 则迭代器将抛出 ConcurrentModificationException 异常。 * 它实现了在列表出现并发修改时的快速失败机制。】 */ protected transient int modCount = 0; /** * 在 ArrayList 尾部新增元素 */ @Override public boolean add(E e) { modCount++; this.add(e, this.elementData, this.size); return true; } /** * 将方法字节码控制在 35(the -XX:MaxInlineSize default value) 个之内,以实现预编译和内联。 */ private void add(E e, Object[] elementData, int s) { // 如果当前元素个数和底层数组长度一致,则需要执行扩容 if (s == elementData.length) { elementData = this.grow(); } // 插入元素 elementData[s] = e; // 增加元素个数 this.size = s + 1; } /** * 默认每次增加一个空间,触发 1.5 倍向下取整扩容 */ private Object[] grow() { return this.grow(this.size + 1); } /** * 增加 ArrayList 的容量以满足最少能容纳 minCapacity 个元素 */ private Object[] grow(int minCapacity) { // 基于数组拷贝实现扩容 return this.elementData = Arrays.copyOf(this.elementData, this.newCapacity(minCapacity)); } /** * 可分配的最大数组大小 */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * 基于预期容量计算新的容量 */ private int newCapacity(int minCapacity) { // overflow-conscious code final int oldCapacity = this.elementData.length; /** * 1.5 倍向下取整扩容 */ final int newCapacity = oldCapacity + (oldCapacity >> 1); /** * 默认扩容后的容量小于预期容量,则以预期容量为准 */ if (newCapacity - minCapacity <= 0) { // 第一次扩容时,取 10 和 minCapacity 的最大值 if (this.elementData == ArrayList.DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(ArrayList.DEFAULT_CAPACITY, minCapacity); } // 预期容量溢出 if (minCapacity < 0) { throw new OutOfMemoryError(); } return minCapacity; } /** * 新的容量小于等于 Integer.MAX_VALUE - 8 则直接返回, * 否则基于预期容量返回 Integer.MAX_VALUE - 8 或 Integer.MAX_VALUE */ return newCapacity - ArrayList.MAX_ARRAY_SIZE <= 0 ? newCapacity : ArrayList.hugeCapacity(minCapacity); } private static int hugeCapacity(int minCapacity) { // 预期容量已经溢出,则抛出 OutOfMemoryError if (minCapacity < 0) { throw new OutOfMemoryError(); } return minCapacity > ArrayList.MAX_ARRAY_SIZE ? Integer.MAX_VALUE : ArrayList.MAX_ARRAY_SIZE; }
4)在指定索引处添加元素
/** * 在指定的位置插入元素 */ @Override public void add(int index, E element) { this.rangeCheckForAdd(index); modCount++; final int s; Object[] elementData; // 当前元素个数等于底层数组容量,则执行扩容 if ((s = this.size) == (elementData = this.elementData).length) { elementData = this.grow(); } // 将目标索引处的元素集体右移一个位置 System.arraycopy(elementData, index, elementData, index + 1, s - index); // 将新元素更新到目标索引处 elementData[index] = element; // 递增元素个数值 this.size = s + 1; } private void rangeCheckForAdd(int index) { if (index > this.size || index < 0) { throw new IndexOutOfBoundsException(this.outOfBoundsMsg(index)); } }
5)将集合中的元素顺序加入到 ArrayList 尾部
/** * 将集合中的元素顺序加入到 ArrayList 尾部 */ @Override public boolean addAll(Collection<? extends E> c) { final Object[] a = c.toArray(); modCount++; // 获取需要添加的元素总个数 final int numNew = a.length; // 集合为空则直接返回 if (numNew == 0) { return false; } Object[] elementData; final int s; // 新增元素个数大于 ArrayList 的剩余容量,则执行扩容,预期容量为 size+newNum if (numNew > (elementData = this.elementData).length - (s = this.size)) { elementData = this.grow(s + numNew); } // 将集合中的元素拷贝到 elementData 数组中 System.arraycopy(a, 0, elementData, s, numNew); // 增加总元素个数 this.size = s + numNew; return true; }
6)获取指定索引处的元素
/** * 获取指定索引处的元素 */ @Override public E get(int index) { // 下标校验 Objects.checkIndex(index, this.size); return this.elementData(index); } // 位置访问操作 /** * 获取指定索引处的元素 * created by ZXD at 15 Jul 2018 T 11:28:00 * @param index * @return */ E elementData(int index) { return (E) this.elementData[index]; }
7)替换指定索引处的元素,并返回旧值
/** * 替换指定索引处的元素,并返回旧值 */ @Override public E set(int index, E element) { // 下标校验 Objects.checkIndex(index, this.size); // 读取旧值 final E oldValue = this.elementData(index); // 更新新值 this.elementData[index] = element; // 返回旧值 return oldValue; }
8)移除指定索引处的元素
/** * 移除指定索引处的元素 */ @Override public E remove(int index) { // 下标校验 Objects.checkIndex(index, this.size); final Object[] es = this.elementData; @SuppressWarnings("unchecked") final E oldValue = (E) es[index]; this.fastRemove(es, index); return oldValue; } /** * 移除元素时,跳过索引校验并且不返回旧元素的值 */ private void fastRemove(Object[] es, int i) { modCount++; final int newSize; // 计算新的 size 值,如果 size 值大于目标索引 if ((newSize = this.size - 1) > i) { // 如果移除索引在数组中间,则目标索引处右侧的元素集体左移一个单位 System.arraycopy(es, i + 1, es, i, newSize - i); } // 将最后一个元素置为 null es[this.size = newSize] = null; }
9)移除指定的目标元素
/** * 通过 {@link Object#equals(Object)} 方法获取第一个匹配的元素并移除 */ @Override public boolean remove(Object o) { final Object[] es = this.elementData; final int size = this.size; int i = 0; // 首先获取目标元素的索引 found: { if (o == null) { for (; i < size; i++) { if (es[i] == null) { break found; } } } else { for (; i < size; i++) { if (o.equals(es[i])) { break found; } } } return false; } // 快速移除目标元素 this.fastRemove(es, i); return true; }
10)移除指定索引间的元素
/** * 移除指定索引范围内的所有元素,包括开始索引,不包括结束索引 */ @Override protected void removeRange(int fromIndex, int toIndex) { if (fromIndex > toIndex) { throw new IndexOutOfBoundsException( ArrayList.outOfBoundsMsg(fromIndex, toIndex)); } modCount++; this.shiftTailOverGap(this.elementData, fromIndex, toIndex); } /** Erases the gap from lo to hi, by sliding down following elements. */ private void shiftTailOverGap(Object[] es, int lo, int hi) { System.arraycopy(es, hi, es, lo, this.size - hi); for (int to = this.size, i = this.size -= hi - lo; i < to; i++) { es[i] = null; } }
11)移除 ArrayList 中包含在目标集合中的所有元素
/** * 移除 ArrayList 中包含在目标集合中的所有元素,通过 {@link Object#equals(Object)} 进行相等性判断 */ @Override public boolean removeAll(Collection<?> c) { return this.batchRemove(c, false, 0, this.size); } /** * created by ZXD at 30 Aug 2018 T 22:16:52 * @param c 目标集合 * @param complement ArrayList 中的元素需要移除还是保留,false 表示移除,true 表示保留 * @param from 开始索引 * @param end 结束索引 * @return */ boolean batchRemove(Collection<?> c, boolean complement, final int from, final int end) { Objects.requireNonNull(c); // 暂存底层数组 final Object[] es = this.elementData; int r; // Optimize for initial run of survivors for (r = from;; r++) { // 如果已经全部遍历完,没有需要处理的元素,则直接返回 if (r == end) { return false; } // 找到第一个需要丢弃的元素下标 if (c.contains(es[r]) != complement) { break; } } // 暂存需要处理元素的下一个位置 int w = r++; try { // 遍历余下的所有元素 for (Object e; r < end; r++) { // 保留满足条件的目标元素 if (c.contains(e = es[r]) == complement) { es[w++] = e; } } } catch (final Throwable ex) { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. System.arraycopy(es, r, es, w, end - r); w += end - r; throw ex; } finally { // 修改并发计数值 modCount += end - w; this.shiftTailOverGap(es, w, end); } return true; }
12)只保留 ArrayList 中包含在目标集合中的所有元素
/** * 保留 ArrayList 中包含在目标集合中的所有元素,通过 {@link Object#equals(Object)} 进行相等性判断 */ @Override public boolean retainAll(Collection<?> c) { return this.batchRemove(c, true, 0, this.size); }原文出处:https://www.cnblogs.com/zhuxudong/p/9581072.html
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦