La colección de Java class-HashMap forma parte de la implementación del código fuente

HashMap

Tanto los valores de clave como de valor de HashMap pueden ser nulos, lo que no es seguro para subprocesos, y no hay garantía de que el orden interno de los elementos no cambie . La estructura de datos subyacente adopta una matriz + una lista enlazada individualmente / árbol rojo-negro , con una matriz de cubos como el cuerpo principal del HashMap, y una lista enlazada o árbol rojo-negro para resolver conflictos de hash.
Inserte la descripción de la imagen aquí

A continuación, aprenda del código fuente de JDK:
la capacidad inicial de HashMap es 16 y el factor de carga predeterminado en el constructor es 0,75.Cuando se alcanza este valor, la matriz se expandirá dos veces .
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
También puede pasar los parámetros de capacidad y factor de carga usted mismo
Inserte la descripción de la imagen aquí
扩容机制:
1. Primero juzgue si la capacidad actual ha alcanzado la capacidad máxima, si ha alcanzado la capacidad máxima, no más expansión.
Inserte la descripción de la imagen aquí
2. Si la capacidad actual excede 16 y la capacidad sigue siendo menor que la capacidad máxima después de duplicarse, la capacidad se duplica.
Inserte la descripción de la imagen aquí
3. Si se trata de una matriz de cubos completamente nueva, asigne la capacidad predeterminada de 16 y el umbral de expansión predeterminado (16 * 0,75 = 12)
Inserte la descripción de la imagen aquí
4. Si el umbral de expansión es 0 (newThr), la expansión se calcula en función de la capacidad actual y factor de carga Valor umbral.
Inserte la descripción de la imagen aquí
5. Finalmente construya una nueva matriz de cubos (newTab) de acuerdo con la capacidad obtenida anteriormente y almacene la matriz original en ella.

this.threshold = newThr;
        HashMap.Node<K, V>[] newTab = new HashMap.Node[newCap];
        this.table = newTab;
        if (oldTab != null) {
    
    
            for(int j = 0; j < oldCap; ++j) {
    
    
                HashMap.Node e;
                if ((e = oldTab[j]) != null) {
    
    
                    oldTab[j] = null;
                    if (e.next == null) {
    
    
                        newTab[e.hash & newCap - 1] = e;
                    } else if (e instanceof HashMap.TreeNode) {
    
    
                        ((HashMap.TreeNode)e).split(this, newTab, j, oldCap);
                    } else {
    
    
                        HashMap.Node<K, V> loHead = null;
                        HashMap.Node<K, V> loTail = null;
                        HashMap.Node<K, V> hiHead = null;
                        HashMap.Node hiTail = null;

                        HashMap.Node next;
                        do {
    
    
                            next = e.next;
                            if ((e.hash & oldCap) == 0) {
    
    
                                if (loTail == null) {
    
    
                                    loHead = e;
                                } else {
    
    
                                    loTail.next = e;
                                }

                                loTail = e;
                            } else {
    
    
                                if (hiTail == null) {
    
    
                                    hiHead = e;
                                } else {
    
    
                                    hiTail.next = e;
                                }

                                hiTail = e;
                            }

                            e = next;
                        } while(next != null);

                        if (loTail != null) {
    
    
                            loTail.next = null;
                            newTab[j] = loHead;
                        }

                        if (hiTail != null) {
    
    
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;
                        }
                    }
                }
            }
        }

        return newTab;

put(K key, V value):
1. Obtenga el valor hash de la clave entrante
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
2. Determine si el valor de la pestaña actual es nulo o si la longitud es 0. Si lo es, realice la operación de expansión.
Inserte la descripción de la imagen aquí
3. Obtenga el subíndice en la tabla del valor hash mediante la función hash. Si no hay ningún elemento en la posición actual, se construye un nuevo nodo y se almacena en la posición actual.
Inserte la descripción de la imagen aquí
4. Si los valores de clave y hash del nodo actual son consistentes con los parámetros pasados, se sobrescribirán.
Inserte la descripción de la imagen aquí
5. Si la ubicación del nodo actual almacena un árbol rojo-negro, inserte el árbol rojo-negro.
Inserte la descripción de la imagen aquí
6. Si la ubicación del nodo actual almacena la lista vinculada, recorra el nodo en el cuarto paso para encontrar el símbolo y sobrescríbalo; de lo contrario, inserte el nodo al final de la lista vinculada y juzgue si es necesario convertirlo en rojo. -Árbol negro y operación de expansión.
Inserte la descripción de la imagen aquí
get(Object key):

El método get es similar al método put. El valor hash correspondiente se obtiene a través del valor clave y luego se convierte en un subíndice de matriz, y luego se recorren y buscan los datos de posición.
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
remove(Object key):
1. Determine si el subíndice correspondiente de la tabla y el valor de clave pasado está vacío
Inserte la descripción de la imagen aquí
. 2. Determine si el primer nodo de la lista vinculada es un nodo de búsqueda
Inserte la descripción de la imagen aquí
. En caso afirmativo, asígnelo al nodo 3. Si la ubicación actual almacena un árbol rojo-negro, utilícelo El método getTreeNode encuentra el nodo.
Inserte la descripción de la imagen aquí
4. Si es una lista vinculada, recorra para encontrar el nodo y asígnelo al nodo.
Inserte la descripción de la imagen aquí
5. El nodo se considera vacío y, al mismo tiempo, se juzga si su valor es igual al parámetro entrante, y luego eliminado.
Inserte la descripción de la imagen aquí
注意: El método equals compara las direcciones de memoria de dos elementos de forma predeterminada, por lo que debemos sobrescribir el método equals para garantizar que el valor de la clave no se repita.

Supongo que te gusta

Origin blog.csdn.net/m0_46550452/article/details/107282080
Recomendado
Clasificación