ArrayList源码分析

UWB灵犀遥控器方案介绍 UWB灵犀指向遥控器的技术原理和方案介绍 阅读详情

概述:

List接口可调整大小的数组实现。实现所有可选的List操作,并允许所有元素,包括null,元素可重复。
除了列表接口外,该类提供了一种方法来操作该数组的大小来存储该列表中的数组的大小。
时间复杂度:
方法size、isEmpty、get、set、iterator和listIterator的调用是常数时间的。
添加删除的时间复杂度为O(N)。其他所有操作也都是线性时间复杂度。
容量:
每个ArrayList都有容量,容量大小至少为List元素的长度,默认初始化为10。
容量可以自动增长。
如果提前知道数组元素较多,可以在添加元素前通过调用ensureCapacity()方法提前增加容量以减小后期容量自动增长的开销。
也可以通过带初始容量的构造器初始化这个容量。
线程不安全:
ArrayList不是线程安全的。
如果需要应用到多线程中,需要在外部做同步

成员变量 elementData:
保存数据的数组。
成员变量 modCount:
定义在AbstractList中:protected transient int modCount = 0;
已从结构上修改此列表的次数。从结构上修改是指更改列表的大小,或者打乱列表,从而使正在进行的迭代产生错误的结果。
此字段由iterator和listiterator方法返回的迭代器和列表迭代器实现使用。
如果意外更改了此字段中的值,则迭代器(或列表迭代器)将抛出concurrentmodificationexception来响应next、remove、previous、set或add操作。
在迭代期间面临并发修改时,它提供了快速失败 行为,而不是非确定性行为。
子类是否使用此字段是可选的。
如果子类希望提供快速失败迭代器(和列表迭代器),则它只需在其 add(int,e)和remove(int)方法(以及它所重写的、导致列表结构上修改的任何其他方法)中增加此字段。
对add(int, e)或remove(int)的单个调用向此字段添加的数量不得超过 1,否则迭代器(和列表迭代器)将抛出虚假的 concurrentmodificationexceptions。
如果某个实现不希望提供快速失败迭代器,则可以忽略此字段。
关键字 transient:
默认情况下,对象的所有成员变量都将被持久化.在某些情况下,如果你想避免持久化对象的一些成员变量,你可以使用transient关键字来标记他们,transient也是java中的保留字(JDK 1.8)

内部类 Itr ( implements Iterator)
提供一种不需要知道集合底层实现就可以遍历的方法。当需要在遍历的时候删除元素,可以使用迭代器的remove方法,而不是直接使用arraylist的remove。(每次遍历一个元素之前都要检查modCount是否等于Itr的expectedmodCount)
clone()浅复制
详见: List的clone()方法

源码分析

package java.util;

import sun.misc.SharedSecrets;

import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;


public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * 默认容量
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 空的对象数组
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 默认的空数组
     * 无参构造函数创建的数组
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 存放数据的数组的缓存变量,不可序列化
     */
    transient Object[] elementData;

    /**
     * 元素数量
     *
     * @serial
     */
    private int size;

    /**
     * 带有容量initialCapacity的构造方法
     *
     * @param 初始容量列表的初始容量
     * @throws IllegalArgumentException 如果指定容量为负
     */
    public ArrayList(int initialCapacity) {
        // 如果初始化时ArrayList大小大于0
        if (initialCapacity > 0) {
            // new一个该大小的object数组赋给elementData
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {// 如果大小为0
            // 将空数组赋给elementData
            this.elementData = EMPTY_ELEMENTDATA;
        } else {// 小于0
            // 则抛出IllegalArgumentException异常
            throw new IllegalArgumentException("Illegal Capacity: " +
                    initialCapacity);
        }
    }

    /**
     * 不带参数的构造方法
     */
    public ArrayList() {
        // 直接将空数组赋给elementData
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**
     * 带参数Collection的构造方法
     *
     * @param c 其元素将被放入此列表中的集合
     * @throws NullPointerException 如果指定的集合是空的
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toarray可能(错误地)不返回对象[](见JAVA BUG编号6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // 使用空数组
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

    /**
     * 因为容量常常会大于实际元素的数量。内存紧张时,可以调用该方法删除预留的位置,调整容量为元素实际数量。
     * 如果确定不会再有元素添加进来时也可以调用该方法来节约空间
     */
    public void trimToSize() {
        modCount++;
        // 如果size小于length
        if (size < elementData.length) {
            // 重新将elementData设置大小为size
            elementData = (size == 0)
                    ? EMPTY_ELEMENTDATA
                    : Arrays.copyOf(elementData, size);
        }
    }

    /**
     * 使用指定参数设置数组容量
     *
     * @param minCapacity 所需的最小容量
     */
    public void ensureCapacity(int minCapacity) {
        //如果数组为空,容量预取0,否则去默认值(10)
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                // any size if not default element table
                ? 0
                // larger than default for default empty table. It's already
                // supposed to be at default size.
                : DEFAULT_CAPACITY;
        //若参数大于预设的容量,在使用该参数进一步设置数组容量
        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

    /**
     * 得到最小扩容量
     *
     * @param minCapacity
     */
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    /**
     * 判断是否需要扩容
     *
     * @param minCapacity
     */
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // 如果最小需要空间比elementData的内存空间要大,则需要扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /**
     * 数组的最大容量,可能会导致内存溢出(VM内存限制)
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 扩容,以确保它可以至少持有由参数指定的元素的数目
     *
     * @param minCapacity 所需的最小容量
     */
    private void grow(int minCapacity) {
        // 获取到ArrayList中elementData数组的内存空间长度
        int oldCapacity = elementData.length;
        // 扩容至原来的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 再判断一下新数组的容量够不够,够了就直接使用这个长度创建新数组,
        // 不够就将数组长度设置为需要的长度
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //若预设值大于默认的最大值检查是否溢出
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 调用Arrays.copyOf方法将elementData数组指向新的内存空间时newCapacity的连续空间
        // 并将elementData的数据复制到新的内存空间
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    /**
     * 检查是否溢出,若没有溢出,返回最大整数值(java中的int为4字节,所以最大为0x7fffffff)或默认最大值
     *
     * @param minCapacity
     * @return
     */
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0)   //溢出
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

    /**
     * 返回ArrayList的大小
     *
     * @return ArrayList中的元素数量
     */
    public int size() {
        return size;
    }

    /**
     * 返回是否为空
     *
     * @return true 如果ArrayList中无元素
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 是否包含一个数 返回bool
     *
     * @param o 检测o是否为ArrayList中元素
     * @return true 如果ArrayList中包含o元素
     */
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }


    /**
     * 返回一个值在数组首次出现的位置,会根据是否为null使用不同方式判断。不存在就返回-1。时间复杂度为O(N)
     *
     * @param o
     * @return
     */
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i] == null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    /**
     * 返回一个值在数组最后一次出现的位置,会根据是否为null使用不同方式判断。不存在就返回-1。时间复杂度为O(N)
     *
     * @param o
     * @return
     */
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size - 1; i >= 0; i--)
                if (elementData[i] == null)
                    return i;
        } else {
            for (int i = size - 1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    /**
     * 返回副本,元素本身没有被复制,复制过程数组发生改变会抛出异常
     *
     * @return v ArrayList副本
     */
    public Object clone() {
        try {
            // 调用父类(翻看源码可见是Object类)的clone方法得到一个ArrayList副本
            ArrayList<?> v = (ArrayList<?>) super.clone();
            // 调用Arrays类的copyOf,将ArrayList的elementData数组赋值给副本的elementData数组
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            // 返回副本v
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

    /**
     * 转换为Object数组,使用Arrays.copyOf()方法
     *
     * @return 一个数组包含所有列表中的元素, 且顺序正确
     */
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

    /**
     * 将ArrayList里面的元素赋值到一个数组中去
     * 如果a的长度小于ArrayList的长度,直接调用Arrays类的copyOf,返回一个比a数组长度要大的新数组,里面元素就是ArrayList里面的元素;
     * 如果a的长度比ArrayList的长度大,那么就调用System.arraycopy,将ArrayList的elementData数组赋值到a数组,然后把a数组的size位置赋值为空。
     *
     * @param a 如果它的长度大的话,列表元素将存储在这个数组中; 否则,将为此分配一个相同运行时类型的新数组。
     * @return 一个包含ArrayList元素的数组
     * @throws ArrayStoreException  将与数组类型不兼容的值赋值给数组元素时抛出的异常
     * @throws NullPointerException 数组为空
     */
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // 创建一个新的a的运行时类型数组,内容不变
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }


    /**
     * 返回指定位置的值,因为是数组,所以速度特别快
     *
     * @param index
     * @return
     */
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

    /**
     * 返回指定位置的值,但是会先检查这个位置数否超出数组长度
     *
     * @param index 要返回的元素的索引
     * @return ArrayList中指定位置的元素
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E get(int index) {
        // 检查是否越界
        rangeCheck(index);
        // 返回ArrayList的elementData数组index位置的元素
        return elementData(index);
    }

    /**
     * 设置指定位置为一个新值,并返回之前的值,会检查这个位置是否超出数组长度
     *
     * @param index   要替换的元素的索引
     * @param element 要存储在指定位置的元素
     * @return 之前在指定位置的元素
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E set(int index, E element) {
        // 检查是否越界
        rangeCheck(index);
        // 调用elementData(index)获取到当前位置的值
        E oldValue = elementData(index);
        // 将element赋值到ArrayList的elementData数组的第index位置
        elementData[index] = element;
        return oldValue;
    }

    /**
     * 添加一个值,首先会确保容量
     *
     * @param e 要添加到此列表中的元素
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        // 扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        // 将e赋值给elementData的size+1的位置
        elementData[size++] = e;
        return true;
    }

    /**
     * 在ArrayList的index位置,添加元素element,会检查添加的位置和容量
     *
     * @param index   指定元素将被插入的索引
     * @param element 要插入的元素
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        // 判断index是否越界
        rangeCheckForAdd(index);
        // 扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
        //src:源数组; srcPos:源数组要复制的起始位置; dest:目的数组; destPos:目的数组放置的起始位置; length:复制的长度
        // 将elementData从index位置开始,复制到elementData的index+1开始的连续空间
        System.arraycopy(elementData, index, elementData, index + 1,
                size - index);
        // 在elementData的index位置赋值element
        elementData[index] = element;
        // ArrayList的大小加一
        size++;
    }

    /**
     * 在ArrayList的移除index位置的元素,会检查添加的位置,返回之前的值
     *
     * @param index 要删除的元素的索引
     * @return 从ArrayList中删除的元素
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E remove(int index) {
        // 判断是否越界
        rangeCheck(index);

        modCount++;
        // 读取旧值
        E oldValue = elementData(index);
        // 获取index位置开始到最后一个位置的个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
            // 将elementData数组index+1位置开始拷贝到elementData从index开始的空间
            System.arraycopy(elementData, index + 1, elementData, index,
                    numMoved);
        // 使size-1 ,设置elementData的size位置为空,让GC来清理内存空间
        elementData[--size] = null; //便于垃圾回收器回收

        return oldValue;
    }

    /**
     * 在ArrayList的移除对象为O的元素,跟indexOf方法思想基本一致
     *
     * @param o 要从该列表中删除的元素(如果存在)
     * @return true 如果这个列表包含指定的元素
     */
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }


    /**
     * 快速删除指定位置的值,之所以叫快速,应该是不需要检查和返回值,因为只内部使用
     *
     * @param index
     */
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index + 1, elementData, index,
                    numMoved);
        // 使size-1 ,设置elementData的size位置为空,让GC来清理内存空间
        elementData[--size] = null; //便于垃圾回收器回收
    }

    /**
     * 清空数组,把每一个值设为null,方便垃圾回收(不同于reset,数组默认大小有改变的话不会重置)
     */
    public void clear() {
        modCount++;

        //便于垃圾回收器回收
        for (int i = 0; i < size; i++)
            elementData[i] = null;
        //把size设置为0,以便我们不会浏览到null值的内存空间
        size = 0;
    }

    /**
     * 添加一个集合的元素到末端,若要添加的集合为空返回false
     *
     * @param c 包含要添加到此列表中的元素的集合
     * @return true 如果该列表因添加而改变
     * @throws NullPointerException 如果指定的集合是空的
     */
    public boolean addAll(Collection<? extends E> c) {
        // 将c转换为数组a
        Object[] a = c.toArray();
        // 获取a占的内存空间长度赋值给numNew
        int numNew = a.length;
        // 扩容至size + numNew
        ensureCapacityInternal(size + numNew);  // Increments modCount
        // 将a的第0位开始拷贝至elementData的size位开始,拷贝长度为numNew
        System.arraycopy(a, 0, elementData, size, numNew);
        // 将size增加numNew
        size += numNew;
        // 如果c为空,返回false,c不为空,返回true
        return numNew != 0;
    }

    /**
     * 从第index位开始,将c全部拷贝到ArrayList,若要添加的集合为空返回false
     *
     * @param index 在哪个索引处插入指定集合中的第一个元素
     * @param c     包含要添加到此列表中的元素的集合
     * @return true 如果该列表因添加而改变
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @throws NullPointerException      如果指定的集合是空的
     */
    public boolean addAll(int index, Collection<? extends E> c) {
        // 判断index大于size或者是小于0,如果是,则抛出IndexOutOfBoundsException异常
        rangeCheckForAdd(index);
        // 将c转换为数组a
        Object[] a = c.toArray();
        int numNew = a.length;
        // 扩容至size + numNew
        ensureCapacityInternal(size + numNew);  // Increments modCount
        // 获取需要添加的个数
        int numMoved = size - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                    numMoved);

        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }

    /**
     * 删除指定范围元素。参数为开始删的位置和结束位置
     *
     * @throws IndexOutOfBoundsException if {@code fromIndex} or
     *                                   {@code toIndex} is out of range
     *                                   ({@code fromIndex < 0 ||
     *                                   fromIndex >= size() ||
     *                                   toIndex > size() ||
     *                                   toIndex < fromIndex})
     */
    protected void removeRange(int fromIndex, int toIndex) {
        modCount++;
        int numMoved = size - toIndex;//后段保留的长度
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                numMoved);

        //便于垃圾回收期回收
        int newSize = size - (toIndex - fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }

    /**
     * 检查index是否超出数组长度 用于添加元素时
     */
    private void rangeCheck(int index) {
        // 如果下标超过ArrayList的数组长度
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /**
     * 检查是否溢出
     */
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /**
     * 抛出的异常的详情
     */
    private String outOfBoundsMsg(int index) {
        return "Index: " + index + ", Size: " + size;
    }

    /**
     * ArrayList移除集合c中的所有元素
     *
     * @param c 包含要从此列表中移除的元素的集合
     * @return {@code true} 如果该列表因移除而改变
     * @throws ClassCastException   if the class of an element of this list
     *                              is incompatible with the specified collection
     *                              (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if this list contains a null element and the
     *                              specified collection does not permit null elements
     *                              (<a href="Collection.html#optional-restrictions">optional</a>),
     *                              or if the specified collection is null
     * @see Collection#contains(Object)
     */
    public boolean removeAll(Collection<?> c) {
        // 如果c为空,则抛出空指针异常
        Objects.requireNonNull(c);
        // 调用batchRemove移除c中的元素
        return batchRemove(c, false);
    }

    /**
     * 仅保留指定集合c中的元素
     *
     * @param c collection containing elements to be retained in this list
     * @return {@code true} if this list changed as a result of the call
     * @throws ClassCastException   if the class of an element of this list
     *                              is incompatible with the specified collection
     *                              (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if this list contains a null element and the
     *                              specified collection does not permit null elements
     *                              (<a href="Collection.html#optional-restrictions">optional</a>),
     *                              or if the specified collection is null
     * @see Collection#contains(Object)
     */
    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        // 调用batchRemove保留c中的元素
        return batchRemove(c, true);
    }

    /**
     * 根据complement值,将ArrayList中包含c中元素的元素删除或者保留
     *
     * @param c
     * @param complement true时从数组保留指定集合中元素的值,为false时从数组删除指定集合中元素的值。
     * @return 数组中重复的元素都会被删除(而不是仅删除一次或几次),有任何删除操作都会返回true
     */
    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        // 定义一个w,一个r,两个同时右移
        int r = 0, w = 0;
        boolean modified = false;
        try {
            // r先右移
            for (; r < size; r++)
                // 如果c中不包含elementData[r]这个元素
                if (c.contains(elementData[r]) == complement)
                    // 则直接将r位置的元素赋值给w位置的元素,w自增
                    elementData[w++] = elementData[r];
        } finally {
            // 防止抛出异常导致上面r的右移过程没完成
            if (r != size) {
                // 将r未右移完成的位置的元素赋值给w右边位置的元素
                System.arraycopy(elementData, r,
                        elementData, w,
                        size - r);
                // 修改w值增加size-r
                w += size - r;
            }
            // 如果有被覆盖掉的元素,则将w后面的元素都赋值为null
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;//改变的次数
                //新的大小为保留的元素的个数
                size = w;
                modified = true;
            }
        }
        return modified;
    }

    /**
     * 保存数组实例的状态到一个流(即序列化)。写入过程数组被更改会抛出异常
     *
     * @serialData The length of the array backing the <tt>ArrayList</tt>
     * instance is emitted (int), followed by all of its elements
     * (each an <tt>Object</tt>) in the proper order.
     */
    private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException {
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        //执行默认的反序列化/序列化过程。将当前类的非静态和非瞬态字段写入此流
        s.defaultWriteObject();

        // 写入大小
        s.writeInt(size);

        // 按顺序写入所有元素
        for (int i = 0; i < size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

    /**
     * 从流中重构ArrayList实例(即反序列化)。
     */
    private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // 执行默认的序列化/反序列化过程
        s.defaultReadObject();

        // 读入数组长度
        s.readInt(); // ignored

        if (size > 0) {
            // 像clone()方法 ,但根据大小而不是容量分配数组
            int capacity = calculateCapacity(elementData, size);
            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
            ensureCapacityInternal(size);

            Object[] a = elementData;
            //读入所有元素
            for (int i = 0; i < size; i++) {
                a[i] = s.readObject();
            }
        }
    }

    /**
     * 返回一个从index开始的ListIterator对象
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: " + index);
        return new ListItr(index);
    }

    /**
     * 返回一个ListIterator对象,ListItr为ArrayList的一个内部类,其实现了ListIterator<E> 接口
     *
     * @see #listIterator(int)
     */
    public ListIterator<E> listIterator() {
        return new ListItr(0);
    }

    /**
     * 返回一个Iterator对象,Itr为ArrayList的一个内部类,其实现了Iterator<E>接口
     *
     * @return an iterator over the elements in this list in proper sequence
     */
    public Iterator<E> iterator() {
        return new Itr();
    }

    /**
     * 通用的迭代器实现
     */
    private class Itr implements Iterator<E> {
        int cursor;       //游标,下一个元素的索引,默认初始化为0
        int lastRet = -1; //上次访问的元素的位置
        int expectedModCount = modCount;//迭代过程不运行修改数组,否则就抛出异常

        //是否还有下一个
        public boolean hasNext() {
            return cursor != size;
        }

        //下一个元素
        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();//检查数组是否被修改
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;//向后移动游标
            return (E) elementData[lastRet = i];//设置访问的位置并返回这个值
        }

        //删除元素
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();//检查数组是否被修改

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        //检查数组是否被修改
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

    /**
     * ListIterator迭代器实现
     */
    private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            super();
            cursor = index;
        }

        public boolean hasPrevious() {
            return cursor != 0;
        }

        public int nextIndex() {
            return cursor;
        }

        public int previousIndex() {
            return cursor - 1;
        }

        @SuppressWarnings("unchecked")
        public E previous() {
            checkForComodification();
            int i = cursor - 1;
            if (i < 0)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i;
            return (E) elementData[lastRet = i];
        }

        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }

    /**
     * Returns a view of the portion of this list between the specified
     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
     * empty.)  The returned list is backed by this list, so non-structural
     * changes in the returned list are reflected in this list, and vice-versa.
     * The returned list supports all of the optional list operations.
     * <p>
     * <p>This method eliminates the need for explicit range operations (of
     * the sort that commonly exist for arrays).  Any operation that expects
     * a list can be used as a range operation by passing a subList view
     * instead of a whole list.  For example, the following idiom
     * removes a range of elements from a list:
     * <pre>
     *      list.subList(from, to).clear();
     * </pre>
     * Similar idioms may be constructed for {@link #indexOf(Object)} and
     * {@link #lastIndexOf(Object)}, and all of the algorithms in the
     * {@link Collections} class can be applied to a subList.
     * <p>
     * <p>The semantics of the list returned by this method become undefined if
     * the backing list (i.e., this list) is <i>structurally modified</i> in
     * any way other than via the returned list.  (Structural modifications are
     * those that change the size of this list, or otherwise perturb it in such
     * a fashion that iterations in progress may yield incorrect results.)
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @throws IllegalArgumentException  {@inheritDoc}
     */
    public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }

    /**
     * 安全检查
     *
     * @param fromIndex
     * @param toIndex
     * @param size
     */
    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                    ") > toIndex(" + toIndex + ")");
    }

    /**
     * 子数组
     */
    private class SubList extends AbstractList<E> implements RandomAccess {
        private final AbstractList<E> parent;
        private final int parentOffset;
        private final int offset;
        int size;

        SubList(AbstractList<E> parent,
                int offset, int fromIndex, int toIndex) {
            this.parent = parent;
            this.parentOffset = fromIndex;
            this.offset = offset + fromIndex;
            this.size = toIndex - fromIndex;
            this.modCount = ArrayList.this.modCount;
        }

        public E set(int index, E e) {
            rangeCheck(index);
            checkForComodification();
            E oldValue = ArrayList.this.elementData(offset + index);
            ArrayList.this.elementData[offset + index] = e;
            return oldValue;
        }

        public E get(int index) {
            rangeCheck(index);
            checkForComodification();
            return ArrayList.this.elementData(offset + index);
        }

        public int size() {
            checkForComodification();
            return this.size;
        }

        public void add(int index, E e) {
            rangeCheckForAdd(index);
            checkForComodification();
            parent.add(parentOffset + index, e);
            this.modCount = parent.modCount;
            this.size++;
        }

        public E remove(int index) {
            rangeCheck(index);
            checkForComodification();
            E result = parent.remove(parentOffset + index);
            this.modCount = parent.modCount;
            this.size--;
            return result;
        }

        protected void removeRange(int fromIndex, int toIndex) {
            checkForComodification();
            parent.removeRange(parentOffset + fromIndex,
                    parentOffset + toIndex);
            this.modCount = parent.modCount;
            this.size -= toIndex - fromIndex;
        }

        public boolean addAll(Collection<? extends E> c) {
            return addAll(this.size, c);
        }

        public boolean addAll(int index, Collection<? extends E> c) {
            rangeCheckForAdd(index);
            int cSize = c.size();
            if (cSize == 0)
                return false;

            checkForComodification();
            parent.addAll(parentOffset + index, c);
            this.modCount = parent.modCount;
            this.size += cSize;
            return true;
        }

        public Iterator<E> iterator() {
            return listIterator();
        }

        public ListIterator<E> listIterator(final int index) {
            checkForComodification();
            rangeCheckForAdd(index);
            final int offset = this.offset;

            return new ListIterator<E>() {
                int cursor = index;
                int lastRet = -1;
                int expectedModCount = ArrayList.this.modCount;

                public boolean hasNext() {
                    return cursor != SubList.this.size;
                }

                @SuppressWarnings("unchecked")
                public E next() {
                    checkForComodification();
                    int i = cursor;
                    if (i >= SubList.this.size)
                        throw new NoSuchElementException();
                    Object[] elementData = ArrayList.this.elementData;
                    if (offset + i >= elementData.length)
                        throw new ConcurrentModificationException();
                    cursor = i + 1;
                    return (E) elementData[offset + (lastRet = i)];
                }

                public boolean hasPrevious() {
                    return cursor != 0;
                }

                @SuppressWarnings("unchecked")
                public E previous() {
                    checkForComodification();
                    int i = cursor - 1;
                    if (i < 0)
                        throw new NoSuchElementException();
                    Object[] elementData = ArrayList.this.elementData;
                    if (offset + i >= elementData.length)
                        throw new ConcurrentModificationException();
                    cursor = i;
                    return (E) elementData[offset + (lastRet = i)];
                }

                @SuppressWarnings("unchecked")
                public void forEachRemaining(Consumer<? super E> consumer) {
                    Objects.requireNonNull(consumer);
                    final int size = SubList.this.size;
                    int i = cursor;
                    if (i >= size) {
                        return;
                    }
                    final Object[] elementData = ArrayList.this.elementData;
                    if (offset + i >= elementData.length) {
                        throw new ConcurrentModificationException();
                    }
                    while (i != size && modCount == expectedModCount) {
                        consumer.accept((E) elementData[offset + (i++)]);
                    }
                    // update once at end of iteration to reduce heap write traffic
                    lastRet = cursor = i;
                    checkForComodification();
                }

                public int nextIndex() {
                    return cursor;
                }

                public int previousIndex() {
                    return cursor - 1;
                }

                public void remove() {
                    if (lastRet < 0)
                        throw new IllegalStateException();
                    checkForComodification();

                    try {
                        SubList.this.remove(lastRet);
                        cursor = lastRet;
                        lastRet = -1;
                        expectedModCount = ArrayList.this.modCount;
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }

                public void set(E e) {
                    if (lastRet < 0)
                        throw new IllegalStateException();
                    checkForComodification();

                    try {
                        ArrayList.this.set(offset + lastRet, e);
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }

                public void add(E e) {
                    checkForComodification();

                    try {
                        int i = cursor;
                        SubList.this.add(i, e);
                        cursor = i + 1;
                        lastRet = -1;
                        expectedModCount = ArrayList.this.modCount;
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }

                final void checkForComodification() {
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                }
            };
        }

        /**
         * 返回指定范围的子数组
         *
         * @param fromIndex
         * @param toIndex
         * @return
         */
        public List<E> subList(int fromIndex, int toIndex) {
            subListRangeCheck(fromIndex, toIndex, size);
            return new SubList(this, offset, fromIndex, toIndex);
        }

        private void rangeCheck(int index) {
            if (index < 0 || index >= this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }

        private void rangeCheckForAdd(int index) {
            if (index < 0 || index > this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }

        private String outOfBoundsMsg(int index) {
            return "Index: " + index + ", Size: " + this.size;
        }

        private void checkForComodification() {
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
        }

        public Spliterator<E> spliterator() {
            checkForComodification();
            return new ArrayListSpliterator<E>(ArrayList.this, offset,
                    offset + this.size, this.modCount);
        }
    }

    @Override
    public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked") final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        for (int i = 0; modCount == expectedModCount && i < size; i++) {
            action.accept(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

    /**
     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
     * list.
     * <p>
     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}.
     * Overriding implementations should document the reporting of additional
     * characteristic values.
     *
     * @return a {@code Spliterator} over the elements in this list
     * @since 1.8
     */
    @Override
    public Spliterator<E> spliterator() {
        return new ArrayListSpliterator<>(this, 0, -1, 0);
    }

    /**
     * Index-based split-by-two, lazily initialized Spliterator
     */
    static final class ArrayListSpliterator<E> implements Spliterator<E> {

        /**
         * 如果ArrayLists是不可变的,或者在结构上不可变(不添加,删除等),我们可以用Arrays.spliterator实现它们的分割器。
         * 相反,我们在遍历期间检测到尽可能多的干扰而不会影响性能。
         * 我们主要依靠modCounts。这些不能保证检测到并发冲突,有时对线程内干扰过于保守,但在实践中检测到足够的问题是值得的。
         * 为了实现这一点,我们
         * (1)懒惰地初始化fence和expectedModCount,直到我们需要提交到我们正在检查的状态的最后一点;从而提高精度。
         * (这不适用于SubLists,它会使用当前非惰性值的分割符)。
         * (2)我们在forEach(对性能最敏感的方法)结束时只执行一次ConcurrentModificationException检查。
         * 当使用forEach(而不是迭代器)时,我们通常只能在行为之后检测干扰,而不是之前。
         * 进一步的CME触发检查适用于所有其他可能的违反假设的情况,例如null或过小的elementData数组,因为它的大小()只能由于干扰而发生。
         * 这允许forEach的内循环在没有任何进一步检查的情况下运行,并且简化了lambda分辨率。虽然这需要进行多次检查,但请注意,在list.stream()。
         * forEach(a)的常见情况中,除forEach本身之外,不会执行任何检查或其他计算。其他较少使用的方法无法利用这些优化的大部分优势。
         */

        private final ArrayList<E> list;
        private int index; // current index, modified on advance/split
        private int fence; // -1 until used; then one past last index
        private int expectedModCount; // initialized when fence set

        /**
         * Create new spliterator covering the given  range
         */
        ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
                             int expectedModCount) {
            this.list = list; // OK if null unless traversed
            this.index = origin;
            this.fence = fence;
            this.expectedModCount = expectedModCount;
        }

        private int getFence() { // initialize fence to size on first use
            int hi; // (a specialized variant appears in method forEach)
            ArrayList<E> lst;
            if ((hi = fence) < 0) {
                if ((lst = list) == null)
                    hi = fence = 0;
                else {
                    expectedModCount = lst.modCount;
                    hi = fence = lst.size;
                }
            }
            return hi;
        }

        public ArrayListSpliterator<E> trySplit() {
            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
            return (lo >= mid) ? null : // divide range in half unless too small
                    new ArrayListSpliterator<E>(list, lo, index = mid,
                            expectedModCount);
        }

        public boolean tryAdvance(Consumer<? super E> action) {
            if (action == null)
                throw new NullPointerException();
            int hi = getFence(), i = index;
            if (i < hi) {
                index = i + 1;
                @SuppressWarnings("unchecked") E e = (E) list.elementData[i];
                action.accept(e);
                if (list.modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                return true;
            }
            return false;
        }

        public void forEachRemaining(Consumer<? super E> action) {
            int i, hi, mc; // hoist accesses and checks from loop
            ArrayList<E> lst;
            Object[] a;
            if (action == null)
                throw new NullPointerException();
            if ((lst = list) != null && (a = lst.elementData) != null) {
                if ((hi = fence) < 0) {
                    mc = lst.modCount;
                    hi = lst.size;
                } else
                    mc = expectedModCount;
                if ((i = index) >= 0 && (index = hi) <= a.length) {
                    for (; i < hi; ++i) {
                        @SuppressWarnings("unchecked") E e = (E) a[i];
                        action.accept(e);
                    }
                    if (lst.modCount == mc)
                        return;
                }
            }
            throw new ConcurrentModificationException();
        }

        public long estimateSize() {
            return (long) (getFence() - index);
        }

        public int characteristics() {
            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
        }
    }

    @Override
    public boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        // figure out which elements are to be removed
        // any exception thrown from the filter predicate at this stage
        // will leave the collection unmodified
        int removeCount = 0;
        final BitSet removeSet = new BitSet(size);
        final int expectedModCount = modCount;
        final int size = this.size;
        for (int i = 0; modCount == expectedModCount && i < size; i++) {
            @SuppressWarnings("unchecked") final E element = (E) elementData[i];
            if (filter.test(element)) {
                removeSet.set(i);
                removeCount++;
            }
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }

        // shift surviving elements left over the spaces left by removed elements
        final boolean anyToRemove = removeCount > 0;
        if (anyToRemove) {
            final int newSize = size - removeCount;
            for (int i = 0, j = 0; (i < size) && (j < newSize); i++, j++) {
                i = removeSet.nextClearBit(i);
                elementData[j] = elementData[i];
            }
            for (int k = newSize; k < size; k++) {
                elementData[k] = null;  // Let gc do its work
            }
            this.size = newSize;
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
            modCount++;
        }

        return anyToRemove;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final int expectedModCount = modCount;
        final int size = this.size;
        for (int i = 0; modCount == expectedModCount && i < size; i++) {
            elementData[i] = operator.apply((E) elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }
}
Spring AI Alibaba实战训练营-14基于A2A协议智能体应用开发指南 本文介绍了基于A2A协议的智能体应用开发流程,主要包括客户端和服务端两个模块的实现。关键技术包括A2A通信协议、Nacos服务发现、Spring AI Alibaba框架和DashScope通义千问API。开发步骤涵盖环境准备(JDK17、Maven、Nacos)、项目创建、依赖配置(重点引入spring-ai-alibaba相关组件)以及Nacos和DashScope的核心配置。整个系统架构采用客户端通过Nacos发现服务端Agent,再调用阿里云AI服务的模式,实现了AI能力的解耦与复用。 阅读详情

相关推荐

Xilinx PCIe IP核示例工程仿真流程与关键任务解析

本文详细解析了Xilinx PCIe IP核示例工程的仿真流程与关键任务。通过搭建仿真环境、解读初始化日志,并深入剖析TSK_TX_MEMORY_WRITE_32等核心任务的TLP报文生成与交互过程,帮助开发者掌握PCIe IP核的仿真调试方法,为实际硬件设计提供可靠的验证基础。

weixin_28314575的博客 509

Java List循环安全删除元素

【代码】Java List循环安全删除元素。

赵先森 3224

解决mamba_ssm库安装难题:两种高效方法详解

本文详细解析了mamba_ssm库安装失败的常见原因,并提供了两种高效的解决方案。针对其依赖C++/CUDA扩展编译的特性,文章手把手指导用户通过GitHub克隆源码编译安装,或寻找匹配的预编译Wheel文件直接安装,帮助开发者彻底解决环境配置难题,顺利部署Mamba模型。

weixin_29056865的博客 554

ArrayList为什么是线程不安全的/多线程修改会出现的问题

ArrayList为线程不安全集合,表现为: 问题一:元素丢失 问题二:数组存在null元素 问题三:数组下标越界ArrayIndexOutOfBoundsException

王如霜 1565

PX4与ROS协同仿真:从键盘控制到无人机自主飞行

本文详细介绍了如何搭建PX4与ROS协同仿真环境,实现从键盘控制到无人机自主飞行的完整流程。通过XTDrone项目整合PX4飞控、ROS通信框架与Gazebo物理引擎,逐步讲解环境配置、键盘控制实现原理,并深入剖析了迈向Offboard模式实现自主飞行的核心代码与数据流,为无人机算法开发与测试提供了安全的仿真沙盒。

weixin_29169899的博客 499

5.4 磁悬浮轴承控制系统仿真:在MATLAB/Simulink中搭建包含功放、传感器模型的闭环系统模型,进行稳定性与动态性能仿真

磁悬浮轴承控制系统仿真方法 摘要:磁悬浮轴承控制系统仿真需建立包含转子动力学、传感器、控制器、功率放大器和电磁执行器的高保真非线性模型。通过MATLAB/Simulink搭建闭环系统,重点建模传感器带宽限制与噪声、功放饱和特性以及电磁力非线性。仿真分析包括时域阶跃响应、扰动抑制测试,频域稳定性分析(伯德图、奈奎斯特图),以及参数摄动下的鲁棒性验证。关键要验证控制算法在非线性因素影响下的稳定性和动态性能,为实际系统实现提供可靠依据。仿真中需特别注意物理量单位一致性和数字控制离散化效应。

技术工作者 1108

【JDK源码分析系列】ArrayList源码分析

【JDK源码分析系列】ArrayList源码分析 【1】ArrayList源码MCL视图 ArrayList的MCL视图如下图所示,包括内部类的MCL视图; 【2】ArrayList源码分析相关知识点总结 /** * 如果用transient声明一个实例变量,当对象存储时,它的值不需要维持; * 即用transient关键字标记的成员变量不参与序列化过程;...

CopperSun 技术博客 612

一分钟学会MATLAB-数据清洗(含完整代码)

数据清洗是数据分析过程中的一个重要步骤,目的是提高数据的质量,以便进行更有效的分析。% 删除超出阈值的行。% 用线性插值填充缺失值。% 删除包含缺失值的行。% 找到缺失值的位置。% 可视化数据,识别异常值。缺失值是数据清洗中常见的问题。通过以上步骤,你可以有效地清洗数据,使其准备好进行后续的分析和建模。

2402_87132195的博客 3316

Java基础之ArrayList源码分析

ArrayList是Java开发中使用比较频繁的一个类,通过对源码的解读,可以了解ArrayList的内部结构以及实现方法,清楚它的优缺点,以便我们在编程时灵活运用。

Soinice的博客 403

Python在Genesis2000 CAM软件中的编程应用

Genesis2000是一款功能强大的计算机辅助制造(CAM)软件,它提供了广泛的功能和工具,用于帮助制造商进行CAD(计算机辅助设计)到CAM的转换。在Genesis2000中,我们可以利用Python的灵活性和功能来扩展软件的自定义能力,并通过编写脚本来自动化各种制造任务。例如,假设我们需要在Genesis2000中添加一个新的操作,用于自动计算零部件的重量。我们可以编写一个Python脚本,通过遍历模型的几何数据并应用相关的计算公式,来实现这个功能。

PixelEnigma的博客 2425

基于YOLO26/11/v8算法的Web目标检测系统,人脸表情识别系统,Django+Vue3 的前后端分离,实现摄像头实时识别,YOLO26/YOLO11/v8 + LLM大模型智能分析,科研必备

在人工智能迈向通用化(AGI)的今天,“视觉感知 + 语言理解”的多模态联合是未来的趋势。单纯的检测画框已经无法满足复杂的业务需求,如何让系统“看懂”画面并进行“思考”,是当前视觉项目的重点。我们知道目标检测是计算机视觉中的重要任务,广泛应用于安防监控、自动驾驶、智能家居等领域。因此本项目将 YOLO 目标检测模型(兼容 YOLO26/v11/v8 系列)与 DeepSeek 等顶流大语言模型(LLM) 进行联合,使用 Django (后端) + Vue3 (前端) 技术栈

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 2841

ArrayList 源码分析

例如,在 Java 中,如果一个对象包含一个基本数据类型的成员变量和一个引用类型的成员变量,进行浅拷贝时,基本数据类型的成员变量会被复制一份,而引用类型的成员变量只是复制了引用,两个对象仍然指向同一个引用对象。浅拷贝是创建一个新的对象,但是这个新对象的成员变量仍然指向原始对象的成员变量所指向的内存地址。也就是说,浅拷贝只是复制了对象的引用,而不是对象的实际内容。在其他编程语言中,如 Python、C++等,也有类似的深拷贝和浅拷贝的概念和实现方式,但具体的语法和方法会有所不同。方法进行实际的容量调整检查。

Wzideng@qq.com 982

3D 韩系风格漫剧人设 | GPT-Image2 人设生成【附完整提示词】

宁姚同款清冷剑系美人,极致小巧鹅蛋脸,下颌线紧致纤细流畅,下巴小巧精致收窄,小脸衬得五官格外舒展,韩式水光肌,面部精细水光高光,鼻梁高光、鼻尖高光、面中苹果肌高光、唇珠高光,红棕色长卷发偏分大波浪,垂在一侧肩前,发量蓬松。发量丰厚蓬松有体积感,不贴头皮,几缕碎发自然垂落脸侧修饰脸型,长度过胸及背,发丝柔顺丝滑卷度自然,发尾自然垂落,身穿香槟色缎面挂脖长裙,挂脖设计无袖露肩露背,上半身围裹式荡领胸口垂褶,腰部堆褶收腰,修身直筒包臀裙长度到脚踝,缎面光泽感强垂坠感好,极简剪裁。纯白色背景,3D漫剧写实厚涂风。

欢迎来到鸾姝淡月博客,专为程序员和编程爱好者打造的技术博客。我们分享编程语言趋势、开发工具、编程哲学、职业发展等,助你掌握新技术,优化技能,激发编程热情。 151

131面试必问:ArrayList源码分析&手写ArrayList

简介 ArrayList是我们开发中非常常用的数据存储容器之一,其底层是数组实现的,我们可以在集合中存储任意类型的数据,ArrayList是线程不安全的,非常适合用于对元素进行查找,效率非常高。 线程安全性 对ArrayList的操作一般分为两个步骤,改变位置(size)和操作元素(e)。所以这个过程在多线程的环境下是不能保证具有原子性的,因此ArrayList在多线程的环境下是线程不安全的。 更多面试题:面试题内容聚合 源码分析 1. 属性分析 /** *默认初始化容量 ...

AI乔治 211

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

ArrayList的源码分析

来源:https://www.cnblogs.com/beppezhang/p/6560710.html 在项目中经常会用到list集合来存储数据,而其中ArrayList是用的最多的的一个集合,这篇博文主要简单介绍ArrayList的源码分析,基于JDK1.7: 这里主要介绍 集合 的属性,构造器,和方法:方法主要基于 add(E e),get(int index),remove(int i...

rentian1的博客 228

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

ArrayList常用方法及源码分析

ArrayList常用方法!!!!!!!!!!!

o676448的博客 418

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Vector,ArrayList,Linkedlist源码分析

list接口和set集合

Cocobuhui的博客 974

Java源码分析之ArrayList

ArrayList源码分析 ArrayList作为一个java中对数据进行存储的容器,是java中List<E>接口的核心实现类 有句古话这么来着:“万变不离其宗”,观其源码,通俗的来说,ArrayList其实就是一个数组 数组众所周知,他的定义必须申请一个规定长度的存储空间,是顺序存储结构,但是ArrayList 似乎可以无限制的添加数据,这是为何,这其实是这种扩容机制系统悄悄地在背后棒你做了 就形成了表面上可以无限制地添加数据的现象 下面,让我们来看看ArrayList的源码分析.

qq_48201696的博客 442

java ArrayList源码分析

ArrayList是 Java 标准库中的一个非常常用的类,它实现了List接口,提供了一个动态数组的实现,可以用来存储一系列的元素。sizeArrayListArrayListArrayListsizeadd(E e)clear()size()ArrayList还实现了一些其他的内部方法和嵌套类,比如Itr(迭代器)、ListItr(列表迭代器)、SubList(子列表)等,这些类和方法支持ArrayList的高级操作,如迭代、元素搜索、子列表操作等。此外,ArrayList还重写了clone()

qq_36070104的博客 1093

ArrayList和LinkedList的区别和源码分析

从源码可以看出,ArrayList想要get(int index)元素时,直接返回index位置上的元素,而LinkedList需要通过for循环进行查找,虽然LinkedList已经在查找方法上做了优化,比如index < size / 2,则从左边开始查找,反之从右边开始查找,但是还是比ArrayList要慢。ArrayList自由性较低,因为它需要手动的设置固定大小的容量,但是它的使用比较方便,只需要创建,然后添加数据,通过调用下标进行使用;//向左挪一位,index位置原来的数据已经被覆盖了。

weixin_62198635的博客 732

ArrayList中add方法源码分析~

首先要明确ArrayList的底层实现是数组利用空参创建的集合时,在底层创建一个默认长度为0的数组添加第一个元素时,底层会创建一个新的长度为10的数组存满时,会扩容1.5倍如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准。

2501_90392153的博客 1905

java集合之ArrayList源码分析

ArrayList是一种以数组实现的List,与数组相比,它具有动态扩展的能力,因此也可称之为动态数组。

2501_92608043的博客 805

源码分析_JDK8 ArrayList源码分析

ArrayList类结构图实现Serializable接口的意义:如果可序列化类未显式声明serialversionUID,则序列化运行时将计算默认的serialVersionUID值。默认的serialversionUID计算是对类细节高度敏感,这些细节可能因编译器而异,因此可能在反序列化过程中可能导致意外的InvalidClassException。因此,为了在不同Java编译器之间保证一致的...

weixin_39841717的博客 70
上一篇: 常见开发框架
下一篇: List的clone()方法
HY_Chan
博客等级 码龄10年 54粉丝 60原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值