Java集合:ArrayList 雨点打透心脏的1/2处 2023-02-25 08:37 52阅读 0赞 ### 类接口 ### 直接上正菜,先看接口 public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ } 接口的解释通常都会出现在接口源码的解释说明的第一行。 **AbstractList抽象类:** 抽象方法+已实现方法,看看就好 **List:** 方法接口 **RandomAccess:** List 实现该标记接口表示它们支持快速随机访问 **Cloneable:** 一个类实现了Cloneable 接口,表示 使用java.lang.Object#clone()方法进行按字段复制是合法的。 **Serializable:** 通过实现java.io.Serializable接口的类,可以启用类的可序列化性。 #### 成员变量 #### 再来看看成员变量 /** * 序列化与反序列化时候用的 */ private static final long serialVersionUID = 8683452581122892189L; /** * Default initial capacity. 默认初始化容量 */ private static final int DEFAULT_CAPACITY = 10; /** * Shared empty array instance used for empty instances. * 当容量为0时,使用该实例 */ private static final Object[] EMPTY_ELEMENTDATA = { }; /** * Shared empty array instance used for default sized empty instances. * 调用空参构造器时,使用该实例 * 我们将其与EMPTY_ELEMENTDATA区别开来,以了解添加第一个元素时需要充气多少。 * 看看ensureCapacityInternal(int minCapacity)方法 */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = { }; /** * The array buffer into which the elements of the ArrayList are stored. * 存储数据的地方 */ transient Object[] elementData; /** * The size of the ArrayList. * 数组的大小 */ private int size; #### 构造方法 #### /** * Constructs an empty list with the specified initial capacity. * * @param initialCapacity the initial capacity of the list */ public ArrayList(int initialCapacity) { //有容量,新建一个initialCapacity大小的数组 if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { //0容量,返回空数组 this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } /** * Constructs an empty list with an initial capacity of ten. * 返回空数组 */ 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. * */ public ArrayList(Collection<? extends E> c) { //集合转数组 elementData = c.toArray(); //转过来的数组不为0时 if ((size = elementData.length) != 0) { if (elementData.getClass() != Object[].class) //把不是Object[].class转成 Object[].class elementData = Arrays.copyOf(elementData,size,Object[].class); } else { //为0,返回空数组 this.elementData = EMPTY_ELEMENTDATA; } } #### 扩容方法 #### /** * Trims the capacity of this ArrayList instance to be the * list's current size. * 让数组压缩到合适大小 */ public void trimToSize() { modCount++; if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } } /** * Increases the capacity of this ArrayList instance * @param minCapacity the desired minimum capacity * 我怎么发现这个方法ArrayList类中都不用的? */ public void ensureCapacity(int minCapacity) { //计算最小的扩展量 int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) // any size if not default element table ? 0 // 如果为空参数构造方法构造的实例,那最小拓展数值为10 : DEFAULT_CAPACITY; if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } } /** * ArrayList中一般使用这个方法来进行扩容活动 */ private void ensureCapacityInternal(int minCapacity) { //如果为空参数构造器构造的实例 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; if (minCapacity - elementData.length > 0) grow(minCapacity); } /** * The maximum size of array to allocate. * Some VMs reserve some header words in an array. * 保留部分位置给虚拟机用 */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * Increases the capacity to ensure that it can hold at least the * number of elements specified by the minimum capacity argument. * * 扩容操作 */ private void grow(int minCapacity) { int oldCapacity = elementData.length; // newCapacity 为元素大小的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // 复制数组 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; } ArrayList在检验是否需要扩容的时候会调用`ensureCapacityInternal(int minCapacity)`方法: 会存在几种扩容情况: 1. elementData == DEFAULTCAPACITY\_EMPTY\_ELEMENTDATA 添加一个元素,扩容到DEFAULT\_CAPACITY 大小 添加一个新集合: 新集合小于等于DEFAULT\_CAPACITY ,扩容到DEFAULT\_CAPACITY; 新集合大于DEFAULT\_CAPACITY ,扩容到新集合; 2. elementData != DEFAULTCAPACITY\_EMPTY\_ELEMENTDATA 添加一个新元素,如果size==elementData .length,容量扩大1.5倍;如果size<elementData .length,数组容量不变。 添加一个新集合,如果size+newArrr.length<=elementData .length,不扩容;反之,扩容1.5倍大小 以上没有考虑极端情况,设计到`MAX_ARRAY_SIZE`的考虑 #### **add方法** #### /** * Appends the specified element to the end of this list. * */ public boolean add(E e) { ensureCapacityInternal(size + 1); elementData[size++] = e; return true; } /** * Inserts the specified element at the specified position in this * list. * 在指定下标位置插入数据 */ public void add(int index, E element) { //边界检查 rangeCheckForAdd(index); ensureCapacityInternal(size + 1); //数组挪位,从index开始的数据都往后走一位 System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } /** * Appends all of the elements in the specified collection to the end of * this list, in the order that they are returned by the specified collection's Iterator. * 在数组的结尾开始插入集合C中的数据 */ public boolean addAll(Collection<? extends E> c) { //转数组对象 Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); System.arraycopy(a, 0, elementData, size, numNew); size += numNew; //c为空数组,则返回false return numNew != 0; } /** * Inserts all of the elements in the specified collection into this * list, starting at the specified position. * 在数组指定下标的位置开始插入集合C中的数据 */ 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) //挪位,空出numNew个位置 System.arraycopy(elementData, index, elementData, index + numNew, numMoved); //入库 System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; } #### **get方法** #### public E get(int index) { //边界检查 rangeCheck(index); return elementData(index); } //简单的检查 private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } #### **set方法** #### public E set(int index, E element) { //边界检查 rangeCheck(index); E oldValue = elementData(index); //新值替换 elementData[index] = element; //返回旧值 return oldValue; } E elementData(int index) { return (E) elementData[index]; } #### **remove方法** #### //移除指定下标的数值 public E remove(int index) { //边界检查 rangeCheck(index); modCount++; E oldValue = elementData(index); //计算需要位移的位数 int numMoved = size - index - 1; if (numMoved > 0) //数组从index+1开始左移一位 System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; } #### 总结: #### 1. ArrayList允许元素重复,元素可以为null 2. 方法不同步,会出现线程安全问题 3. 容器的初始容量为10,每次扩容后的容量为原始容量的1.5倍,添加集合情况另算。 4. ArrayList的动态数组实现基于Arrays和System类的数组拷贝赋值方法
还没有评论,来说两句吧...