Análisis del código fuente de ArrayList (sin terminar)

Análisis de código fuente ArrayList

Introducción

Características: ArrayList es la principal clase de implementación de la interfaz List, que almacena datos ordenados y repetibles.

Ventajas y desventajas: el hilo ArrayList no es seguro, pero su eficiencia de consulta y modificación de datos es alta.

El principio subyacente: la capa inferior de ArrayList se implementa en función de matrices.

Herencia e implementación de Arraylist

Diagrama de clases de ArrayList (el diagrama es generado automáticamente por Idea)

Inserte la descripción de la imagen aquí
Como se puede ver en la figura anterior, ArrayList hereda AbstractList e implementa Serializable, RandomAccess, Cloneable y List.

Características:

  • Herede la clase AbstractList e implemente la interfaz List. Es una clase abstracta que implementa algunas operaciones de List relacionadas con la posición (como obtener, establecer, agregar, eliminar). Es la primera clase de colección que implementa métodos de acceso aleatorio, pero no admite la adición y reemplazo .
  • Implemente la interfaz Cloneable y reescriba la función clone (), que se puede clonar.
  • Implemente la interfaz RandomAccess y proporcione la función de acceso aleatorio.
  • La interfaz serializable está implementada, por lo que ArrayList admite la serialización y puede convertir objetos en un proceso que se puede mantener o transmitir.

Análisis de código fuente

Este artículo analizará el código fuente desde la perspectiva del uso de ArrayList

Propiedades de ArrayList

Antes de leer el código fuente, debemos comprender el significado de algunos atributos de ArrayList

	// 数组默认的初始容量为10
    private static final int DEFAULT_CAPACITY = 10;

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

	// 空的Object数组,将其与上面的区分开来,EMPTY_ELEMENTDATA用于有参构造函数且参数为0时,而DEFAULTCAPACITY_EMPTY_ELEMENTDATA用于无参构造函数。
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
    
    };

	// 集合中存放数据的对象,ArrayList的核心
    transient Object[] elementData; 

	// 集合内数据的大小,size初始为0
    private int size;

	// modCount继承于AbstractList,用于记录数组的添加、删除操作次数

Crear un objeto ArrayList

  1. Crea un objeto usando un constructor sin parámetros

    ArrayList arr = new ArrayList();
    

    Use Ctrl + clic izquierdo del mouse en Idea para ingresar a ArrayList.java y ver el código fuente.

    // 可以看出,创建了一个elementData的长度为0的ArrayList对象
    public ArrayList() {
          
          
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    
  2. Utilice un constructor parametrizado para crear un objeto y el tipo de parámetro es int.

    // 创建一个长度为initialCapacity的elementData数组
    public ArrayList(int initialCapacity) {
          
          
        // 如果初始容量长度大于0,则从新创建一个Object数组
        if (initialCapacity > 0) {
          
          
            this.elementData = new Object[initialCapacity];
        // 否则如果初始容量为0,则将EMPTY_ELEMENTDATA的地址赋给elementData。  
        } else if (initialCapacity == 0) {
          
          
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
          
          
        // 否则抛出异常    
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
    
  3. Utilice el constructor parametrizado para crear un objeto, y el tipo de parámetro es Colección.

    // 使用这种方式创建ArrayList对象,会将Collection对象转为Object数组,然后将其拷贝给elementData数组
    public ArrayList(Collection<? extends E> c) {
          
          
        // 将Collection对象转为数组
        Object[] a = c.toArray();
        // 将b数组的长度赋值给size,判断其是否不等于0
        if ((size = a.length) != 0) {
          
          
            if (c.getClass() == ArrayList.class) {
          
          
                // 将a的地址赋给elementData
                elementData = a;
            } else {
          
          
                // 进行拷贝操作
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
          
          
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }
    

Agregar datos a la colección arrayList

1 、 agregar (E e)

agregar (E e) método

Función: Este método consiste en pasar los datos y agregarlos a la matriz en la forma de autoincremento de la matriz.

    public boolean add(E e) {
    
    
        // 判断集合内存储元素的个数加1看其是否可以承受这个容量
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

asegurarCapacidadInternal (int minCapacidad) 方法

Función: para garantizar que la capacidad interna de la matriz pueda agregar nuevos datos

    private void ensureCapacityInternal(int minCapacity) {
    
    
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

calcularCapacidad (Object [] elementData, int minCapacity) 方法

Función: Compare el tamaño de minCapacity (tamaño + 1) y DEFAULT_CAPACITY (10) y devuelva el valor máximo.

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

asegurarExplicitCapacity (int minCapacity) 方法

Función: minCapacity, para determinar si su tamaño es mayor que la longitud de la matriz, si es mayor que la longitud de la matriz, la matriz debe expandirse

modCount ++: El número de modificaciones de la matriz +1 y la función de este atributo se discutirán más adelante.

    private void ensureExplicitCapacity(int minCapacity) {
    
    
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

método grow (int minCapacity)

Función: expandir la matriz

    private void grow(int minCapacity) {
    
    
        // 将数组的长度定义为集合中旧的容量
        int oldCapacity = elementData.length;
        // 将新的容量定义为旧的容量的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 如果新的容量小于旧的容量,就令新的容量等于旧的容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        // 如果新的容量减去最大数组长度(Integer.MAX_VALUE - 8),则令新的容量扩充为int类型的最大取值范围
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 将旧的数组的数据复制到新的数组中去
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

En este punto, después de completar el juicio previo sobre la expansión de la matriz, se agregan nuevos datos a la matriz.

elementData[size++] = e;
        return true;

Importante: cuando se inicializa la colección, es una matriz vacía, y solo cuando se agregan datos por primera vez, su longitud será 10

2 、 agregar (índice int, elemento E)

método add (índice int, elemento E)

Función: la función de este método es insertar elementos en la colección de acuerdo con la posición especificada

    public void add(int index, E element) {
    
    
        // 用于add和addAll的范围检查,判断是否越界,否则抛出异常。
        rangeCheckForAdd(index);

        // 确保数组内部容量可以添加新的数据
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        // 将elementData中从index开始的数据拷贝到elementData从index+1开始的位置。
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        // 将element元素添加到指定的index位置上
        elementData[index] = element;
        // 集合大小+1
        size++;
    }

3 、 addAll (Colección <? Extiende E> c)

Función: agregue los datos de la colección a la colección arrayList

    public boolean addAll(Collection<? extends E> c) {
    
    
        // 将集合转为数组
        Object[] a = c.toArray();
        int numNew = a.length;
        // 确保数组的容量可以添加这些数据,如果不行就扩容
        ensureCapacityInternal(size + numNew);  // Increments modCount
        // 将a数组内的元素添加到elementData[size]之后.
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

Eliminar los datos de la colección arrayList

1 、 eliminar (índice int)

Función: quitar el elemento en la posición especificada

    public E remove(int index) {
    
    
        // 查看index是否不在集合范围中
        rangeCheck(index);

        // 修改次数+1
        modCount++;
        // 返回指定删除位置上的元素
        E oldValue = elementData(index);

        // 将指定位置后的元素集体向前移动一位
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        // 令原本最后的位置上的元素为空
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

2 、 eliminar (Objeto o)

Función: eliminar el elemento especificado

// 通过for循环遍历数组,获取需要删除元素的下标,通过remove删除。
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;
    }

3 、 removeRange (int fromIndex, int toIndex)

Función: eliminar elementos en el rango de índice a índice

    protected void removeRange(int fromIndex, int toIndex) {
    
    
        // 修改次数+1
        modCount++;
        // 需要向前移动的的长度
        int numMoved = size - toIndex;
        
        // 将toIndex后的元素向前移动numMoved
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved);

        // clear to let GC do its work
        int newSize = size - (toIndex-fromIndex);
        // 通过for循环置从newSize开始的元素为空
        for (int i = newSize; i < size; i++) {
    
    
            elementData[i] = null;
        }
        // 更新size的大小
        size = newSize;
    }

Devuelve el elemento en la posición especificada.

obtener (índice)

// 先进行范围检查,然后直接返回数组中下标为index的元素    
public E get(int index) {
    
    
    // index不能>=当前集合的大小
    rangeCheck(index);

    return elementData(index);
}

Actualizar el elemento en la posición especificada

set (índice int, elemento E)

// 先进行范围检查,然后获取指定位置上的元素,然后存放到oldValue中,将需要更新的元素赋值给elementData[index],最后返回旧的数据。
public E set(int index, E element) {
    
    
    // index不能>=当前集合的大小
    rangeCheck(index);

    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

Determinar si un determinado elemento está contenido en la colección.

contiene (Objeto o)

Función: determinar si un determinado elemento está incluido en la colección

public boolean contains(Object o) {
    
    
	// 判断下标是否大于等于0(表示元素存在)
    return indexOf(o) >= 0;
}

indexOf (Objeto o)

Función: Obtener el subíndice del elemento existente en la colección.

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;
    }
    // 返回-1表示元素不存在
    return -1;
}

Borrar todos los datos de la colección

public void clear() {
    
    
    // 修改次数+1
    modCount++;

    // 使用for循环令数组中全部的元素都为空
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}

Nota: Al eliminar o borrar elementos de la colección, el tamaño de los datos de la colección cambiará, pero la longitud de la matriz no cambiará.

Obtenga los elementos en el rango especificado en la colección

subList (int fromIndex, int toIndex) 方法

Función: obtener los elementos en el rango especificado en la colección

public List<E> subList(int fromIndex, int toIndex) {
    
    
    // 先进性范围检查,查看fromIndex、toIndex是否满足1条件
    subListRangeCheck(fromIndex, toIndex, size);
    
    // 返回一个新创建的SubList对象,将需要获取的范围传入其中。
    return new SubList(this, 0, fromIndex, toIndex);
}

Clase SubList

Introducción: Es una clase interna de la clase ArrayList, su función es la misma que la de la clase ArrayList, puede obtener los elementos en la posición especificada en el arreglo en lugar de interceptarlos para convertirlos en un nuevo arreglo.

Las funciones de modificación, eliminación, adición y consulta también se definen en la clase SubList.

Iterador

método iterator ()

Devuelve un objeto Itr recién creado

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

Itr clase

Introducción: esta clase, como la clase SubList, también es una clase interna. Itr implementa la interfaz Iterator. Entonces podemos usarlo para atravesar.

mecanismo a prueba de fallas

Introducción: en el uso de ArrayList, se puede generar una excepción, y la mayor parte de esta excepción se produce cuando se utilizan varios subprocesos.

El nombre de esta excepción es ConcurrentModificationException.

Causa: cuando varios subprocesos operan en la colección al mismo tiempo, un subproceso itera en la colección y asigna el modCount de este período de tiempo a la propiedad esperabaModCount en la clase Itr, mientras que otros subprocesos operan en la colección en el mismo período de tiempo. modCount se actualizará, pero esperabaModCount no se actualizará. Habrá un método (checkForComodification ()) en el iterador para comparar los valores de modCount y esperabaModCount, por lo que cuando los dos valores no son iguales, se producirá una excepción ser arrojado. Este es el mecanismo a prueba de fallas.

Al mismo tiempo, esta es la razón por la que la colección ArrayList no es segura.

Propósito de falla rápida : un mecanismo propuesto para prevenir problemas de seguridad de subprocesos al leer datos.

Para obtener más información, consulte la publicación de este blogger.

Conexión de referencia:

https://blog.csdn.net/zymx14/article/details/78394464

Para resolver el problema de seguridad del subproceso, podemos usar CopyOnWriteArrayList en lugar de ArrayList.

Supongo que te gusta

Origin blog.csdn.net/weixin_43898463/article/details/114668460
Recomendado
Clasificación