Miron Asked:2020-12-19 20:10:43 +0000 UTC2020-12-19 20:10:43 +0000 UTC 2020-12-19 20:10:43 +0000 UTC 向 ArrayList 添加元素的机制是什么? 772 这个过程在内部是如何安排的ArrayList?我想知道实施细节。它是如何作用于价值观的?特别是grow(). java 1 个回答 Voted Best Answer Miron 2020-12-19T20:10:43Z2020-12-19T20:10:43Z 首先,让我们找出可以增加 ArrayList 的方法。 1) 使用方法add(T element) 2) 使用方法add(int index, T element) 3) 使用方法addAll(Collection<? extends T> c) 4) 使用方法addAll(int index, Collection<? extends T> c) 让我们分别分析每种方法: 1)这是方法源代码add(T element): public boolean add(E e) { modCount++; add(e, elementData, size); return true; } 它增加一个变量modCount(结构转换的数量)。以下是 javadoc 1.4 的摘录: 该字段由迭代器使用,实现了迭代器和 listIterator 方法返回的迭代器的实现。如果此字段的值意外更改,迭代器(或列表迭代器)将抛出 ConcurrentModificationException 以响应以下操作:remove、previous、set 或 add。这提供了容错行为,而不是在迭代期间面对并发修改时的不确定行为。 然后调用方法add(E e, Object[], int s)。然后它返回 true,因为它应该返回这个值,因为它在Collection.add(E e). 我们来分析一下这个方法add(E e, Object[] elementData, int s)。这是源代码: private void add(E e, Object[] elementData, int s) { if (s == elementData.length) elementData = grow(); elementData[s] = e; size = s + 1; } 在一个变量中e- 我们创建的元素。在变量elementData中 - 所有元素的数组(可能未完全填充),以及s- 实际位于元素数组中的元素数量。如果数组没有完全填满,我们向数组中添加一个元素,并增加包含实际定位元素数量的变量。否则,除此之外,我们首先使用grow(). 我们来分析一下这个方法grow()。这是源代码: private Object[] grow() { return grow(size + 1); } 这意味着它只调用了另一个grow方法,但是使用参数int minCapacity,我们将包含实际定位元素数量的变量的值加1。这是它的源代码: private Object[] grow(int minCapacity) { int oldCapacity = elementData.length; if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { int newCapacity = ArraysSupport.newLength(oldCapacity, minCapacity - oldCapacity, /* minimum growth */ oldCapacity >> 1 /* preferred growth */); return elementData = Arrays.copyOf(elementData, newCapacity); } else { return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)]; } } 如果数组不为空,那么我们将原始数组的长度增加等于旧长度的一半(向下舍入),如果结果长度不大于最大数组长度(Integer.MAX_VALUE - 8),否则等于最大数组长度,如果oldLength + minGrowth小于最大数组长度,否则等于Integer.MAX_VALUE。 否则,我们重新初始化数组,将引用传递给长度为 10 或minCapacity如果minCapacity> 10的对象数组。 如果有人对代码感兴趣ArraysSupport.newLength,这里是源代码(我刚刚从 java 13 找到它们): public static int newLength(int oldLength, int minGrowth, int prefGrowth) { // assert oldLength >= 0 // assert minGrowth > 0 int newLength = Math.max(minGrowth, prefGrowth) + oldLength; if (newLength - MAX_ARRAY_LENGTH <= 0) { return newLength; } return hugeLength(oldLength, minGrowth); } private static int hugeLength(int oldLength, int minGrowth) { int minLength = oldLength + minGrowth; if (minLength < 0) { // overflow throw new OutOfMemoryError("Required array length too large"); } if (minLength <= MAX_ARRAY_LENGTH) { return MAX_ARRAY_LENGTH; } return Integer.MAX_VALUE; } 方法分析add(T element)结束。 2)这是方法源代码add(int index, T element): public void add(int index, E element) { rangeCheckForAdd(index); modCount++; final int s; Object[] elementData; if ((s = size) == (elementData = this.elementData).length) elementData = grow(); System.arraycopy(elementData, index, elementData, index + 1, s - index); elementData[index] = element; size = s + 1; } rangeCheckForAdd(int index)index如果它不在真实元素中,则抛出错误。modCount 传统上会增加。然后我们在没有空间容纳新元素的情况下使用方法增加数组的长度grow(),并将所有元素移到需要插入元素的索引的右侧,将要插入的对象插入到产生“空白”。内部长度变量传统上是递增的。 3)这是方法源代码addAll(Collection<? extends T> c): public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray(); modCount++; int numNew = a.length; if (numNew == 0) return false; Object[] elementData; final int s; if (numNew > (elementData = this.elementData).length - (s = size)) elementData = grow(s + numNew); System.arraycopy(a, 0, elementData, s, numNew); size = s + numNew; return true; } modCount传统上增加。我们从集合中获取一个数组,以便我们可以使用标准方法插入一个数组。如果要插入的集合为空,则返回false。如果插入的集合不适合数组,我们增加它。然后我们将“集合”添加到数组的最后。内部长度变量传统上是递增的。我们报告工作的顺利完成。 4)这是方法源代码addAll(int index, Collection<? extends T> c): public boolean addAll(int index, Collection<? extends E> c) { rangeCheckForAdd(index); Object[] a = c.toArray(); modCount++; int numNew = a.length; if (numNew == 0) return false; Object[] elementData; final int s; if (numNew > (elementData = this.elementData).length - (s = size)) elementData = grow(s + numNew); int numMoved = s - index; if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); size = s + numNew; return true; } rangeCheckForAdd(int index)执行与插入单个元素时相同的功能。我们所做的一切都与 中相同addAll(Collection<? extends T> c),直到创建一个变量numMoved,它存储包含后的真实数组元素的数量index(请记住,迭代从 0 开始!)。如果它们确实存在,那么我们将它们移到右侧,为插入的集合腾出空间。然后将集合插入到以 开头的范围内index。内部长度变量传统上是递增的。我们报告工作的顺利完成。 感谢您的关注。如果您发现错误或不准确之处 - 请告诉我,我愿意接受任何批评。
首先,让我们找出可以增加 ArrayList 的方法。
1) 使用方法
add(T element)2) 使用方法
add(int index, T element)3) 使用方法
addAll(Collection<? extends T> c)4) 使用方法
addAll(int index, Collection<? extends T> c)让我们分别分析每种方法:
1)这是方法源代码
add(T element):它增加一个变量
modCount(结构转换的数量)。以下是 javadoc 1.4 的摘录:然后调用方法
add(E e, Object[], int s)。然后它返回 true,因为它应该返回这个值,因为它在Collection.add(E e).我们来分析一下这个方法
add(E e, Object[] elementData, int s)。这是源代码:在一个变量中
e- 我们创建的元素。在变量elementData中 - 所有元素的数组(可能未完全填充),以及s- 实际位于元素数组中的元素数量。如果数组没有完全填满,我们向数组中添加一个元素,并增加包含实际定位元素数量的变量。否则,除此之外,我们首先使用grow().我们来分析一下这个方法
grow()。这是源代码:这意味着它只调用了另一个grow方法,但是使用参数
int minCapacity,我们将包含实际定位元素数量的变量的值加1。这是它的源代码:如果数组不为空,那么我们将原始数组的长度增加等于旧长度的一半(向下舍入),如果结果长度不大于最大数组长度(
Integer.MAX_VALUE - 8),否则等于最大数组长度,如果oldLength + minGrowth小于最大数组长度,否则等于Integer.MAX_VALUE。否则,我们重新初始化数组,将引用传递给长度为 10 或
minCapacity如果minCapacity> 10的对象数组。如果有人对代码感兴趣
ArraysSupport.newLength,这里是源代码(我刚刚从 java 13 找到它们):方法分析
add(T element)结束。2)这是方法源代码
add(int index, T element):rangeCheckForAdd(int index)index如果它不在真实元素中,则抛出错误。modCount 传统上会增加。然后我们在没有空间容纳新元素的情况下使用方法增加数组的长度grow(),并将所有元素移到需要插入元素的索引的右侧,将要插入的对象插入到产生“空白”。内部长度变量传统上是递增的。3)这是方法源代码
addAll(Collection<? extends T> c):modCount传统上增加。我们从集合中获取一个数组,以便我们可以使用标准方法插入一个数组。如果要插入的集合为空,则返回false。如果插入的集合不适合数组,我们增加它。然后我们将“集合”添加到数组的最后。内部长度变量传统上是递增的。我们报告工作的顺利完成。4)这是方法源代码
addAll(int index, Collection<? extends T> c):rangeCheckForAdd(int index)执行与插入单个元素时相同的功能。我们所做的一切都与 中相同addAll(Collection<? extends T> c),直到创建一个变量numMoved,它存储包含后的真实数组元素的数量index(请记住,迭代从 0 开始!)。如果它们确实存在,那么我们将它们移到右侧,为插入的集合腾出空间。然后将集合插入到以 开头的范围内index。内部长度变量传统上是递增的。我们报告工作的顺利完成。感谢您的关注。如果您发现错误或不准确之处 - 请告诉我,我愿意接受任何批评。