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.AbstractCollection
Esta clase proporciona una Collection
implementación de la interfaz a nivel de esqueleto.
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
AbstractCollection
La 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 AbstractCollection
las iterator
funciones y size
funciones 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 AbstractCollection
necesario no solo implementar dos de los métodos abstractos, sino también implementar el add
método y asegurarse de que iterator
el método remove se implemente en el iterador devuelto por la función.
Para los algoritmos no abstractos, AbstractCollection
la sugerencia es: si hay un método de implementación más eficiente, las subclases pueden anularlo (anular)