ArrayList
1.ArrayList存储结构
数组(数组是采用一段连续的存储单元来存储数据)
特点,查询快O(1)。删除插入慢(O(N))
数组查找遵循下面公式
数组 a[n] = 起始位置+(n*字节数);
2.ArrayList代码实现
2.1 首先看类的继承,实现关系。
继承了AbstractList,实现了List,RandomAccess, Cloneable, java.io.Serializable。
List ???(比较奇怪,AbstractList里面也实现了这个接口,这里又继承了,很奇怪。不知道为啥)
RandomAccess随机访问(get方法)
Cloneable 拷贝
Serializable序列化
2.2 基本属性
int DEFAULT_CAPACITY = 10; 数组初始化大小
Object[] EMPTY_ELEMENTDATA = {} ;空数组 用于有参构造创建数组。代码中能估算出list放多少数据,可以直接指定长度,优化速度。
Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};空数组 用于无参构造,就是一个空数组。
transient Object[] elementData; arrayList真正存放元素的地方,长度大于等于size
size 数组长度
2.3.构造方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | /** * Constructs an empty list with the specified initial capacity. * * @param initialCapacity the initial capacity of the list * @throws IllegalArgumentException if the specified initial capacity * is negative */ // 当 initialCapacity 为零时则是把 EMPTY_ELEMENTDATA 赋值给 elementData。 // 当 initialCapacity 大于零时初始化一个大小为 initialCapacity 的 object 数组并赋值给 elementData。 public ArrayList( int initialCapacity) { if (initialCapacity > 0 ) { this .elementData = new Object[initialCapacity]; } else if (initialCapacity == 0 ) { this .elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException( "Illegal Capacity: " + initialCapacity); } } /** * Constructs an empty list with an initial capacity of ten. */ //无参构造器,构造一个容量大小为 10 的空的 list 集合,但构造函数只是给 elementData 赋值了一个空的数组,其实是在第一次添加元素时容量扩大至 10 的。 public ArrayList() { this .elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /** * Constructs a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ //将 Collection 转化为数组,数组长度赋值给 size。 //如果 size 不为零,则判断 elementData 的 class 类型是否为 ArrayList,不是的话则做一次转换。 //如果 size 为零,则把 EMPTY_ELEMENTDATA 赋值给 elementData,相当于new ArrayList(0)。 public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0 ) { // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[]. class ) elementData = Arrays.copyOf(elementData, size, Object[]. class ); } else { // replace with empty array. this .elementData = EMPTY_ELEMENTDATA; } } |
3.常用的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @return <tt>true</tt> (as specified by {@link Collection#add}) */ //直接尾部添加元素。 public boolean add(E e) { ensureCapacityInternal(size + 1 ); // Increments modCount!! elementData[size++] = e; return true ; } //指定下标添加元素 public void add( int index, E element) { //下标越界检查 rangeCheckForAdd(index); //容量检查 ensureCapacityInternal(size + 1 ); //依次复制插入位置及后面的数组元素,到后面一格。 //因此复制完后,添加的下标位置和下一个位置指向对同一个对象 System.arraycopy(elementData, index, elementData, index + 1 , size - index); //再将元素赋值给该下标 elementData[index] = element; size++; } |
1 | 3.1 ensureCapacityInternal里面有个扩容的操作 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | private void grow( int minCapacity) { //获取当前数组长度 int oldCapacity = elementData.length; //默认将扩容至原来容量的 1.5 倍 int newCapacity = oldCapacity + (oldCapacity >> 1 ); //如果1.5倍太小的话,则将我们所需的容量大小赋值给newCapacity if (newCapacity - minCapacity < 0 ) newCapacity = minCapacity; //如果1.5倍太大或者我们需要的容量太大, //那就直接拿 newCapacity = hugeCapacity(minCapacity) //(minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE 来扩容 // MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; if (newCapacity - MAX_ARRAY_SIZE > 0 ) newCapacity = hugeCapacity(minCapacity); //然后将原数组中的数据复制到大小为 newCapacity 的新数组中, //并将新数组赋值给 elementData。 elementData = Arrays.copyOf(elementData, newCapacity); } |
3.2 list迭代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | private class Itr implements Iterator<E> { // 代表下一个要访问的元素下标 int cursor; // 代表上一个要访问的元素下标 int lastRet = - 1 ; //代表对 ArrayList 修改次数的期望值,初始值为 modCount //如果下一个元素的下标等于集合的大小 ,就证明到最后了 int expectedModCount = modCount; Itr() {} public boolean hasNext() { return cursor != size; } @SuppressWarnings ( "unchecked" ) public E next() { checkForComodification(); int i = cursor; //对 cursor 进行判断,看是否超过集合大小和数组长度 if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList. this .elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); //自增 1。开始时,cursor = 0,lastRet = -1; //每调用一次next方法,cursor和lastRet都会自增1。 cursor = i + 1 ; ////将cursor赋值给lastRet,并返回下标为 lastRet 的元素 return (E) elementData[lastRet = i]; } public void remove() { //判断 lastRet 的值是否小于 0 if (lastRet < 0 ) throw new IllegalStateException(); checkForComodification(); try { //直接调用 ArrayList 的 remove 方法删除下标为 lastRet 的元素 ArrayList. this .remove(lastRet); cursor = lastRet; //将 lastRet 重新赋值为 -1, lastRet = - 1 ; //将 modCount 重新赋值给 expectedModCount。 expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } //判断expectedModCount和modCount是否相等 //ConcurrentModificationException final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } |
本文来自博客园,作者:mfzcq,转载请注明原文链接:https://www.cnblogs.com/xhld19/p/15780085.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理