Java中ArrayList类的方法(源码)

Posted 美少女降临人世间

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中ArrayList类的方法(源码)相关的知识,希望对你有一定的参考价值。

文章目录

ArrayList中的方法

  • 以下内容是基于JDK 11的API整理的,对add、remove、get、set、toString方法在工具中查看了源码,剩下的罗列出了API中的方法便于速览。

创建数组: 实例化data对象,并指定泛型类型

ArrayList<Integer> data = new ArrayList<>();

一、add

添加数据: 调用add方法

data.add(100);//增加内容,此方法是从Collection接口继承而来,可以传入一个参数
  • 存储时需要存储Integer类型数据,传入的int型会自动装箱为Integer类型数据。此时数组长度为0,若想存储数据,需要进行扩容,而add就对数据进行扩容操作

点开add源码,结果return的是true。

/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return @code true (as specified by @link Collection#add)
*/
public boolean add(E e) 
    modCount++;
    add(e, elementData, size);
    return true;
  • 只要调用add方法,永远返回true。

再点开add中传入3个参数的add方法:

/**
* This helper method split out from add(E) to keep method
* bytecode size under 35 (the -XX:MaxInlineSize default value),
* which helps when add(E) is called in a C1-compiled loop.
*/
private void add(E e, Object[] elementData, int s) 
    if (s == elementData.length)
        elementData = grow();
    elementData[s] = e;
    size = s + 1;
  • 如果目前寸的数据和数组长度一致,说明存满了,此时用grow方法对其进行扩容,重新赋值给elementData。

最后点开grow方法,看到底是如何对数组进行扩容的。

/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private Object[] grow(int minCapacity) 
    return elementData = Arrays.copyOf(elementData,
                                       newCapacity(minCapacity));


private Object[] grow() 
    return grow(size + 1);
  • 如果数组满了,最少给数组长度+1。定义一个新的数组长度,再使用Arrays.copyOf将旧数组的值,通过新的数组长度,赋值给旧数组。

查看newCapacity方法,用来计算新的长度:

/**
* Returns a capacity at least as large as the given minimum capacity.
* Returns the current capacity increased by 50% if that suffices.
* Will not return a capacity greater than MAX_ARRAY_SIZE unless
* the given minimum capacity is greater than MAX_ARRAY_SIZE.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private int newCapacity(int minCapacity) 
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity <= 0) 
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return minCapacity;
    
    return (newCapacity - MAX_ARRAY_SIZE <= 0)
        ? newCapacity
        : hugeCapacity(minCapacity);


private static int hugeCapacity(int minCapacity) 
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE)
        ? Integer.MAX_VALUE
        : MAX_ARRAY_SIZE;
  • 新数组长度为: oldCapacity + oldCapacity >> 1

    >> 1指二进制右移一位,相当于除2,0.5倍。

  • 这里的默认长度DEFAULT_CAPACITY为10

    /**
    * Default initial capacity.
    */
    private static final int DEFAULT_CAPACITY = 10;

二、get和set

1、get

获取集合中的数据

data.get(0);

点开get方法查看源码:先用checkIndex对传入的下标进行检查,返回elementData(index)

/**
* Returns the element at the specified position in this list.
*
* @param  index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException @inheritDoc
*/
public E get(int index) 
    Objects.checkIndex(index, size);
    return elementData(index);
  • 给elementData传入一个index

查看checkIndex:

/**
 * Checks if the @code index is within the bounds of the range from
 * @code 0 (inclusive) to @code length (exclusive).
 *
 * <p>The @code index is defined to be out of bounds if any of the
 * following inequalities is true:
 * <ul>
 *  <li>@code index < 0</li>
 *  <li>@code index >= length</li>
 *  <li>@code length < 0, which is implied from the former inequalities</li>
 * </ul>
 *
 * @param index the index
 * @param length the upper-bound (exclusive) of the range
 * @return @code index if it is within bounds of the range
 * @throws IndexOutOfBoundsException if the @code index is out of bounds
 * @since 9
 */
@ForceInline
public static
int checkIndex(int index, int length) 
    return Preconditions.checkIndex(index, length, null);
  • 再点进此处传入三个参数的checkIndex方法:

    /**
     * Checks if the @code index is within the bounds of the range from
     * @code 0 (inclusive) to @code length (exclusive).
     *
     * <p>The @code index is defined to be out of bounds if any of the
     * following inequalities is true:
     * <ul>
     *  <li>@code index < 0</li>
     *  <li>@code index >= length</li>
     *  <li>@code length < 0, which is implied from the former inequalities</li>
     * </ul>
     *
     * <p>If the @code index is out of bounds, then a runtime exception is
     * thrown that is the result of applying the following arguments to the
     * exception formatter: the name of this method, @code checkIndex;
     * and an unmodifiable list integers whose values are, in order, the
     * out-of-bounds arguments @code index and @code length.
     *
     * @param <X> the type of runtime exception to throw if the arguments are
     *        out of bounds
     * @param index the index
     * @param length the upper-bound (exclusive) of the range
     * @param oobef the exception formatter that when applied with this
     *        method name and out-of-bounds arguments returns a runtime
     *        exception.  If @code null or returns @code null then, it is as
     *        if an exception formatter produced from an invocation of
     *        @code outOfBoundsExceptionFormatter(IndexOutOfBounds::new) is used
     *        instead (though it may be more efficient).
     *        Exceptions thrown by the formatter are relayed to the caller.
     * @return @code index if it is within bounds of the range
     * @throws X if the @code index is out of bounds and the exception
     *         formatter is non-@code null
     * @throws IndexOutOfBoundsException if the @code index is out of bounds
     *         and the exception formatter is @code null
     * @since 9
     *
     * @implNote
     * This method is made intrinsic in optimizing compilers to guide them to
     * perform unsigned comparisons of the index and length when it is known the
     * length is a non-negative value (such as that of an array length or from
     * the upper bound of a loop)
    */
    @HotSpotIntrinsicCandidate
    public static <X extends RuntimeException>
    int checkIndex(int index, int length,
                   BiFunction<String, List<Integer>, X> oobef) 
        if (index < 0 || index >= length)
            throw outOfBoundsCheckIndex(oobef, index, length);
        return index;
    
    • 对下标进行检查,如果下标<0或>=数组长度就抛出异常,终止程序

查看elementData,返回的是数组index下标对应的值:

@SuppressWarnings("unchecked")
E elementData(int index) 
    return (E) elementData[index];

2、set

用指定的元素替换此列表中指定位置的元素

data.set(0,100);

点开set查看源码:

/**
 * Replaces the element at the specified position in this list with
 * the specified element.
 *
 * @param index index of the element to replace
 * @param element element to be stored at the specified position
 * @return the element previously at the specified position
 * @throws IndexOutOfBoundsException @inheritDoc
 */
public E set(int index, E element) 
    Objects.checkIndex(index, size);
    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
  • 可以看到将传入的element数据赋值给index下标对应的位置进行替换。

三、toString

对集合内容进行输出:直接对data打印,默认调用了toString方法

data.toString();

点开toString的源码:

/**
* Returns a string representation of this collection.  The string
* representation consists of a list of the collection's elements in the
* order they are returned by its iterator, enclosed in square brackets
* (@code "[]").  Adjacent elements are separated by the characters
* @code ", " (comma and space).  Elements are converted to strings as
* by @link String#valueOf(Object).
*
* @return a string representation of this collection
*/
public String toString() 
    Iterator<E> it = iterator();
    if (! it.hasNext())
        return "[]";

    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) 
        E e = it.next();
        sb.append(e == this ? "(this Collection)" : e);
        if (! it.hasNext())
            return sb.append(']').toString();
        sb.append(',').append(' ');
    
  • 对集合数据进行格式化,添加了方括号和逗号

四、remove

对数据进行删除

data.remove(0);

点开remove的源码:

/**
 * Removes the element at the specified position in this list.
 * Shifts any subsequent elements to the left (subtracts one from their
 * indices).
 *
 * @param index the index of the element to be removed
 * @return the element that was removed from the list
 * @throws IndexOutOfBoundsException @inheritDoc
 */
public E remove(int index) 
    Objects.checkIndex(index, size);
    final Object[] es = elementData;

    @SuppressWarnings("unchecked") E oldValue = (E) es[index];
    fastRemove(es, index);

    return oldValue;
  • 有一个fastRemove方法,传入es和index,es是定义为fianl的elementData

查看fastRemove:

/**
 * Private remove method that skips bounds checking and does not
 * return the value removed.
 */
private void fastRemove(Object[] es, int i) 
    modCount++;
    final int newSize;
    if ((newSize = size - 1) > i)
        System.arraycopy(es, i + 1, es, i, newSize - i);
    es[size = newSize] = null;
  • 定义一个新的数组长度为旧数组长度-1,使用arraycopy方法将指定源数组中的数组从指定位置开始复制到目标数组的指定位置。

    • System中的arraycopy方法:API中的解释

      public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

      将指定源数组中的数组从指定位置开始复制到目标数组的指定位置。 阵列组件的一个子序列被从通过引用的源阵列复制src被引用的目标阵列dest 。 复制的组件数等于length参数。 在位置的部件srcPos通过srcPos+length-1源阵列中的被复制到的位置destPos通过destPos+length-1分别,目的地阵列。

其他

API中ArrayList所有方法速览:

变量和类型方法描述
voidadd(int index, E element)将指定元素插入此列表中的指定位置。
booleanadd(E e)将指定的元素追加到此列表的末尾。
booleanaddAll(int index, Collection<? extends E> c)从指定位置开始,将指定集合中的所有元素插入此列表。
booleanaddAll(Collection<? extends E> c)将指定集合中的所有元素按指定集合的Iterator返回的顺序附加到此列表的末尾。
voidclear()从此列表中删除所有元素。
Objectclone()返回此 ArrayList实例的浅表副本。
booleancontains(Object o)如果此列表包含指定的元素,则返回 true
voidensureCapacity(int minCapacity)如有必要,增加此 ArrayList实例的容量,以确保它至少可以容纳由minimum capacity参数指定的元素数。
voidforEach(Consumer<? super E> action)Iterable每个元素执行给定操作,直到处理 Iterable所有元素或操作引发异常。
Eget(int index)返回此列表中指定位置的元素。
intindexOf(Object o)返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
booleanisEmpty()如果此列表不包含任何元素,则返回 true
Iterator<E>iterator()以适当的顺序返回此列表中元素的迭代器。
intlastIndexOf(Object o)返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
ListIterator<E>listIterator()返回此列表中元素的列表迭代器(按适当顺序)。
ListIterator<E>listIterator(int index)从列表中的指定位置开始,返回列表中元素的列表迭代器(按正确顺序)。
Eremove(int index)删除此列表中指定位置的元素。
booleanremove(Object o)从该列表中删除指定元素的第一个匹配项(如果存在)。
booleanremoveAll(Collection<?> c)从此列表中删除指定集合中包含的所有元素。
booleanremoveIf(Predicate<? super E> filter)删除此集合中满足给定谓词的所有元素。
protected voidremoveRange(int fromIndex, int toIndex)从此列表中删除索引介于 fromIndex (含)和 toIndex (独占)之间的所有元素。
booleanretainAll(Collection<?> c)仅保留此列表中包含在指定集合中的元素。
Eset(int index, E element)用指定的元素替换此列表中指定位置的元素。
intsize()返回此列表中的元素数。
Spliterator<E>spliterator()在此列表中的元素上创建late-binding和故障快速Spliterator
List<E>subList(int fromIndex, int toIndex)返回指定的 fromIndex (包含)和 toIndex (不包括)之间的此列表部分的视图。
Object[]toArray()以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。
<T> T[]toArray(T[] a)以适当的顺序返回包含此列表中所有元素的数组(从第一个元素到最后一个元素); 返回数组的运行时类型是指定数组的运行时类型。
List<E>subList(int fromIndex, int toIndex)返回指定的 fromIndex (包含)和 toIndex (不包括)之间的此列表部分的视图。
Object[]toArray()以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。
<T> T[]toArray(T[] a)以适当的顺序返回包含此列表中所有元素的数组(从第一个元素到最后一个元素); 返回数组的运行时类型是指定数组的运行时类型。
voidtrimToSize()将此 ArrayList实例的容量调整为列表的当前大小。

总结

ArrayList是List接口的子类,在我们开发中经常使用,对于ArrayList的方法,最好亲自在API中进行检索查看,那里讲解会更加全面。

以上是关于Java中ArrayList类的方法(源码)的主要内容,如果未能解决你的问题,请参考以下文章

23.Java基础_ArrayList类

JAVA源码走读 HashMap与ArrayList

Java Review - ArrayList 源码解读

Java集合框架 List接口实现类--LinkedList类的使用 & 源码分析 & LinkedList与ArrayList类的区别

java List子类源码分析

Java源码之ArrayList