Análisis del código fuente JDK de java.util.AbstractCollection

La clase AbstractCollection proporciona los métodos básicos que debe tener la clase de implementación de la colección y tiene cierta universalidad.Puedes comprender las funciones principales de la clase de implementación de la colección a partir de la situación general.

java.util.AbstractCollectionEsta clase proporciona una Collectionimplementación de la interfaz a nivel de esqueleto.

Inserte la descripción de la imagen aquí

Uno, análisis de código fuente

1. Iterador (): devuelve un objeto iterador

public abstract Iterator<E> iterator();

2. size (): devuelve el tamaño de la colección

public abstract int size();

3. isEmpty (): determina si está vacío

public boolean isEmpty() {
    
    
        return size() == 0;
}

4. contiene (Objeto o): si debe contener el elemento especificado

    public boolean contains(Object o) {
    
    
        Iterator<E> it = iterator();
        if (o==null) {
    
    
            while (it.hasNext())
                if (it.next()==null)
                    return true;
        } else {
    
    
            while (it.hasNext())
                if (o.equals(it.next()))
                    return true;
        }
        return false;
    }

5 、 toArray ()

En la función toArray(), primero inicialice una matriz de acuerdo con el tamaño actual de la colección y establezca el número esperado de elementos de acuerdo con el tamaño de la colección. Luego use el iterador para recorrer los elementos de la colección uno por uno, si se encuentra que los elementos de la colección se han eliminado desde el i-ésimo, entonces devuelva directamente los primeros elementos i en r.
Si se encuentra que luego de iniciada la conversión, se inserta un nuevo elemento en la colección, ingresará al ciclo de expansión + replicación. La parte de expansión amplía la capacidad de la matriz a 1,5 veces la original. Cuando la capacidad de la matriz se llena nuevamente durante el proceso de copia, la capacidad se expande nuevamente. Finalmente, se devuelven todos los elementos válidos de la matriz.

Nota: La copia de este algoritmo no es 100% precisa, solo puede garantizar que el número de elementos en la matriz es el mismo que el número de elementos atravesados ​​por el iterador de colección, y el orden es el mismo, en lugar de asegurar que los elementos en la matriz sean los mismos que los elementos de la colección .

5.1, convierte la colección en una matriz
    public Object[] toArray() {
    
    
        // Estimate size of array; be prepared to see more or fewer elements
        Object[] r = new Object[size()];
        Iterator<E> it = iterator();
        for (int i = 0; i < r.length; i++) {
    
    
            if (! it.hasNext()) // fewer elements than expected
                return Arrays.copyOf(r, i);
            r[i] = it.next();
        }
        return it.hasNext() ? finishToArray(r, it) : r;
    }
5.2. Convertir la colección en una matriz especificada
    public <T> T[] toArray(T[] a) {
    
    
        // Estimate size of array; be prepared to see more or fewer elements
        int size = size();
        T[] r = a.length >= size ? a :
                  (T[])java.lang.reflect.Array
                  .newInstance(a.getClass().getComponentType(), size);
        Iterator<E> it = iterator();

        for (int i = 0; i < r.length; i++) {
    
    
            if (! it.hasNext()) {
    
     // fewer elements than expected
                if (a == r) {
    
    
                    r[i] = null; // null-terminate
                } else if (a.length < i) {
    
    
                    return Arrays.copyOf(r, i);
                } else {
    
    
                    System.arraycopy(r, 0, a, 0, i);
                    if (a.length > i) {
    
    
                        a[i] = null;
                    }
                }
                return a;
            }
            r[i] = (T)it.next();
        }
        // more elements than expected
        return it.hasNext() ? finishToArray(r, it) : r;
    }

5.3. Operación de expansión y asignación. Cuando el subíndice i y la longitud de la matriz r.length son iguales, la expansión se realiza una vez y finalmente se devuelve una matriz del tamaño de los elementos de la matriz.
    private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
    
    
        int i = r.length;
        while (it.hasNext()) {
    
    
            int cap = r.length;
            if (i == cap) {
    
    
                int newCap = cap + (cap >> 1) + 1;
                // overflow-conscious code
                if (newCap - MAX_ARRAY_SIZE > 0)
                    newCap = hugeCapacity(cap + 1);
                r = Arrays.copyOf(r, newCap);
            }
            r[i++] = (T)it.next();
        }
        // trim if overallocated
        return (i == r.length) ? r : Arrays.copyOf(r, i);
    }
    private static int hugeCapacity(int minCapacity) {
    
    
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError
                ("Required array size too large");
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

6. add (): si la subclase puede agregar elementos, el método add debe reescribirse

public boolean add(E e) {
    
    
        throw new UnsupportedOperationException();
    }

7, eliminar (Objeto o): aplica un iterador para eliminar un elemento

    public boolean remove(Object o) {
    
    
        Iterator<E> it = iterator();
        if (o==null) {
    
    
            while (it.hasNext()) {
    
    
                if (it.next()==null) {
    
    
                    it.remove();
                    return true;
                }
            }
        } else {
    
    
            while (it.hasNext()) {
    
    
                if (o.equals(it.next())) {
    
    
                    it.remove();
                    return true;
                }
            }
        }
        return false;
    }

8. containsAll (Collection <?> C): si incluir todos los elementos de la matriz especificada

    public boolean containsAll(Collection<?> c) {
    
    
        for (Object e : c)
            if (!contains(e))
                return false;
        return true;
    }

9, addAll (Collection <? Extiende E> c): llama al método add cíclicamente

    public boolean addAll(Collection<? extends E> c) {
    
    
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }

10. removeAll (Collection <?> C): elimina los mismos elementos que la colección de parámetros de entrada

    public boolean removeAll(Collection<?> c) {
    
    
        Objects.requireNonNull(c);
        boolean modified = false;
        Iterator<?> it = iterator();
        while (it.hasNext()) {
    
    
            if (c.contains(it.next())) {
    
    
                it.remove();
                modified = true;
            }
        }
        return modified;
    }

11. keepAll (Collection <?> C): conserva los mismos elementos que los elementos en el conjunto de parámetros

    public boolean retainAll(Collection<?> c) {
    
    
        Objects.requireNonNull(c);
        boolean modified = false;
        Iterator<E> it = iterator();
        while (it.hasNext()) {
    
    
            if (!c.contains(it.next())) {
    
    
                it.remove();
                modified = true;
            }
        }
        return modified;
    }

12.clear () borra todos los elementos de la colección

    public void clear() {
    
    
        Iterator<E> it = iterator();
        while (it.hasNext()) {
    
    
            it.next();
            it.remove();
        }
    }

13, toString (): reescribe el método toString

    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(' ');
        }
    }

2. Expandir

1. El constructor protegido de AbstractCollection

La clase abstracta AbstractCollection en realidad tiene un constructor protegido

protected AbstractCollection() {
    
    }

Sobre el método de construcción protegido de la clase abstracta:

  • En primer lugar, es absolutamente correcto que las clases abstractas no pueden instanciarse, por lo que las clases abstractas no pueden contener métodos de construcción públicos;

  • El constructor protegido de la clase abstracta se llama implícitamente, por lo que super () no se llama necesariamente explícitamente en el constructor de sus subclases, aunque esto se recomienda para AbstractCollection;

  • El constructor protegido de la clase abstracta se puede utilizar para inicializar ciertas propiedades en la clase para evitar la aparición de un mensaje.

2. Colección de solo lectura, colección editable

AbstractCollectionLa clase de implementación se divide en dos tipos, uno es una colección de solo lectura y el otro es una colección modificable.

En una colección de solo lectura, solo se requieren AbstractCollectionlas iteratorfunciones y sizefunciones en la implementación , y otras funciones pueden permanecer sin cambios (bajo la premisa de que no hay ningún requisito para el rendimiento), lo que garantiza que la implementación de la clase solo requiere una pequeña cantidad de trabajo, y luego la colección La función se realiza básicamente.

Para una colección modificable, es AbstractCollectionnecesario no solo implementar dos de los métodos abstractos, sino también implementar el addmétodo y asegurarse de que iteratorel método remove se implemente en el iterador devuelto por la función.

Para los algoritmos no abstractos, AbstractCollectionla sugerencia es: si hay un método de implementación más eficiente, las subclases pueden anularlo (anular)

Supongo que te gusta

Origin blog.csdn.net/weixin_45187434/article/details/108868602
Recomendado
Clasificación