# Detalles del marco de recopilación de Java

Detalles del marco de recopilación de Java

Mapa de descripción general del marco de recopilación

Inserte la descripción de la imagen aquí

Interfaz iterable

La interfaz Iterable es la interfaz de nivel superior del marco de la colección de Java. La implementación de esta interfaz puede atravesar sus propios elementos a través de un iterador. En el contenedor de Java, Collection hereda la interfaz Iterable.

Código fuente de interfaz iterable

public interface Iterable<T> {
    
    
	// 创建一个类型为T的Iterator的实例
    Iterator<T> iterator();

    // 遍历操作集合内的元素
    default void forEach(Consumer<? super T> action) {
    
    
        Objects.requireNonNull(action);
        for (T t : this) {
    
    
            action.accept(t);
        }
    }
    // 并行遍历元素的迭代器
    default Spliterator<T> spliterator() {
    
    
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

Interfaz de iterador

La interfaz Iterator proporciona operaciones en elementos como hasNext () y next (). La implementación de la clase Iterator completa las operaciones de elementos específicos. La clase interna anónima en la subclase de Colección implementará la interfaz Iterator para operar en los elementos del contenedor.


Interfaz de colección

La interfaz de Colección define métodos como atributos de elementos y métodos de elementos.

@Test
public void test1(){
    
    

    Collection list = new ArrayList();
    Collection linkList = new LinkedList();
    Collection set = new HashSet();
    Collection linkSet = new LinkedHashSet();
    Collection queue = new ArrayDeque();
    Collection deQueue = new DelayQueue();
}

Heredar la interfaz de Collection

Lista

La interfaz List amplía los métodos en la interfaz Collection.


Lista de arreglo
public class ArrayList<E> extends AbstractList<E>        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
    
    }

Inserte la descripción de la imagen aquí

  • Descripción general de ArrayList : ArrayList se implementa en función de matrices y se puede expandir dinámicamente. ArrayList no es seguro para subprocesos y se da cuenta de la
    interfaz serializable para poder serializar la transmisión. Admite acceso aleatorio rápido e implementa la interfaz Cloneable para implementar la clonación de objetos.
  • Inicialización de ArrayList
// 默认无参构造函数
public ArrayList() ;
// 制定大小初始化
public ArrayList(int initialCapacity);
// Collection实例初始化
public ArrayList(Collection<? extends E> c)
  • Expansión dinámica ArrayList : en add ()
// 最具体的扩容方法
private void grow(int minCapacity) {
    
    
    // 目前数组的长度
    int oldCapacity = elementData.length;
    // 新的数组的大小 旧数组大小+就数组大小右移1位
    // newCapacity =oldCapacity + 0.5 * oldCapacity  
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // MAX_ARRAY_SIZE 为int最大值减去8
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

Si se construye sin parámetros, la capacidad inicial de la matriz es 0. Cuando la matriz se agrega realmente, la capacidad se asigna realmente. Siga oldCapacity + (oldCapacity >> 1) cada vez. Expansión mediante copeOf.


Colocar

La interfaz Set hereda los métodos de la interfaz Collection de la extensión Collection,

Relación de clase HashSet

Inserte la descripción de la imagen aquí


Interfaz Java.util.Map

Relación de clase HashMap
public class HashMap<K,V> extends AbstractMap<K,V>    implements Map<K,V>, Cloneable, Serializable {
    
    }

Inserte la descripción de la imagen aquí

Estructura de almacenamiento subyacente de HashMap

HashMap es una colección que se utiliza para almacenar pares clave-valor clave-valor, y cada par clave-valor también se denomina Entrada. Tanto la clave como el valor en HashMap pueden ser nulos.

  • Matriz : los elementos de la matriz se almacenan en forma de Entrada <K, V>.
/**
  * Basic hash bin node, used for most entries.  (See below for
  * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
  */
static class Node<K,V> implements Map.Entry<K,V> {
    
    
    // 定位数组索引位置
    final int hash;
    final K key;
    V value;
    // 链表的下一个节点
    Node<K,V> next; 

    Node(int hash, K key, V value, Node<K,V> next) {
    
    
        this.hash = hash;
        this.key = key;
        this.value = value;
        this.next = next;
    }
    public final K getKey()        {
    
     return key; }
    public final V getValue()      {
    
     return value; }
    public final String toString() {
    
     return key + "=" + value; }
    public final int hashCode() {
    
    }
    public final V setValue(V newValue) {
    
    }
    public final boolean equals(Object o) {
    
    }
}
  • Lista enlazada
  • Árbol rojo-negro : cuando la lista vinculada es demasiado larga, se convierte en un árbol rojo-negro, y cuando la longitud de la lista vinculada es demasiado larga (el valor predeterminado es más de 8), la lista vinculada se convierte en un árbol rojo-negro. Utilice el árbol rojo-negro para agregar, eliminar, modificar y verificar rápidamente para mejorar el rendimiento de HashMap. Entre ellos, se utilizan algoritmos de inserción, eliminación y búsqueda de árbol rojo-negro.
HashMap usa almacenamiento de tabla hash
  • Map.put ("nombre", "Zhang San")

Llame a hashCode () para calcular el valor hash de name y ubique la ubicación de almacenamiento del par clave-valor mediante la operación de orden superior y la operación de módulo del algoritmo hash. Cuando el valor hashCode de la clave es el mismo, se produce una colisión hash. Un buen algoritmo hash y un mecanismo de expansión pueden reducir la probabilidad de colisiones hash.

int threshold;             // 所能容纳的key-value对极限 
final float loadFactor;    // 负载因子
int modCount;  // 记录HashMap内部结构发生变化的次数
int size; // Map中存的键值对数量
  • La longitud inicial de la tabla Node [K, V] [] es 16 , el factor de carga (el valor predeterminado es 0,75 ) y el umbral es el número de nodos (pares clave-valor) con la cantidad máxima de datos que puede HashMap sostener. umbral = longitud * factor de carga . En otras palabras, una vez definida la longitud de la matriz, cuanto mayor sea el factor de carga, más pares clave-valor se pueden acomodar.
  • El umbral es el número máximo de elementos permitidos bajo el factor de carga y la longitud correspondientes (longitud de la matriz). Si se excede este número, se cambiará de tamaño (se ampliará). La capacidad ampliada de HashMap es el doble de la capacidad anterior.
HashMap determina la posición del índice de la matriz
  • índice hashCode
  • Aritmética alta
  • Operación de módulo: la operación h & (longitud-1) es equivalente a tomar la longitud del módulo, que es h% de longitud, pero & tiene mayor eficiencia que%.
static final int hash(Object key) {
    
    
    int h;
    // 计算key的hash值 h = key.hashCode()
    // 高位参与运算 h^(h>>>16) h异或(h右移16位)
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
Mecanismo de expansión

Inserte la descripción de la imagen aquí

  • Cambiar el tamaño es recalcular la capacidad y agregar elementos al objeto HashMap continuamente.Cuando la matriz dentro del objeto HashMap no puede cargar más elementos, el objeto necesita expandir la longitud de la matriz para que se puedan cargar más elementos. Por supuesto, la matriz en Java no se puede expandir automáticamente. El método es usar una nueva matriz para reemplazar la matriz existente con una capacidad pequeña, al igual que usamos un balde pequeño para almacenar agua. Si queremos almacenar más agua, hay que cambiar el cubo grande.
final Node<K,V>[] resize() {
    
    
    Node<K,V>[] oldTab = table;
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    int oldThr = threshold;
    int newCap, newThr = 0;
    if (oldCap > 0) {
    
    
         //若容量超过最大值,则无法进行扩容,需扩大阀值
        if (oldCap >= MAXIMUM_CAPACITY) {
    
    
            threshold = Integer.MAX_VALUE;
            return oldTab;
        }
         // 没超过最大值,就扩充为原来的2倍
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                 oldCap >= DEFAULT_INITIAL_CAPACITY)
            newThr = oldThr << 1; // double threshold
    }
    else if (oldThr > 0) // initial capacity was placed in threshold
        newCap = oldThr;
    else {
    
                   // zero initial threshold signifies using defaults
        newCap = DEFAULT_INITIAL_CAPACITY;
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
     // 计算新的resize上限
    if (newThr == 0) {
    
    
        float ft = (float)newCap * loadFactor;
        newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                  (int)ft : Integer.MAX_VALUE);
    }
    threshold = newThr;
    @SuppressWarnings({
    
    "rawtypes","unchecked"})
    Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    table = newTab;
    if (oldTab != null) {
    
    
	 	//for循环把oldTab中的每个节点node,reHash操作并移动到新的数组newTab中
        for (int j = 0; j < oldCap; ++j) {
    
    
            Node<K,V> e;
            if ((e = oldTab[j]) != null) {
    
    
                oldTab[j] = null;
                // 若是单个节点,即没有后继next节点,则直接 newTab 在进行重定位
                if (e.next == null)
                    newTab[e.hash & (newCap - 1)] = e;
                //若节点为TreeNode,则需要进行红黑树的rehash操作
                else if (e instanceof TreeNode)
                    ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                //else则节点为链表,需进行链表的rehash操作,链表重组并保持原有顺序
                else {
    
     // preserve order
                    Node<K,V> loHead = null, loTail = null;
                    Node<K,V> hiHead = null, hiTail = null;
                    Node<K,V> next;
                    do {
    
    
                        next = e.next;
                        //通过与位运算&,判断rehash后节点位置是否发生改变
                        if ((e.hash & oldCap) == 0) {
    
    
                            if (loTail == null)
                                //loHead 指向新的 hash 在原位置的头节点
                                loHead = e;
                            else
                                //loTail 指向新的 hash 在原位置的尾节点
                                loTail.next = e;
                            loTail = e;
                        }
                        //else则rehash后节点位置变为:原位置+oldCap位置
                        else {
    
    
                            if (hiTail == null)
                                hiHead = e;
                            else
                                hiTail.next = e;
                            hiTail = e;
                        }
                    } while ((e = next) != null);
                    if (loTail != null) {
    
    
                        loTail.next = null;
                        newTab[j] = loHead;
                    }
                    if (hiTail != null) {
    
    
                        hiTail.next = null;
                        newTab[j + oldCap] = hiHead;
                    }
                }
            }
        }
    }
    return newTab;
}

Supongo que te gusta

Origin blog.csdn.net/qq_37248504/article/details/113574720
Recomendado
Clasificación