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.
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 .
También puede pasar los parámetros de capacidad y factor de carga usted mismo
扩容机制
:
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.
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.
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)
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.
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
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.
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.
4. Si los valores de clave y hash del nodo actual son consistentes con los parámetros pasados, se sobrescribirán.
5. Si la ubicación del nodo actual almacena un árbol rojo-negro, inserte el árbol rojo-negro.
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.
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.
remove(Object key)
:
1. Determine si el subíndice correspondiente de la tabla y el valor de clave pasado está vacío
. 2. Determine si el primer nodo de la lista vinculada es un nodo de búsqueda
. 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.
4. Si es una lista vinculada, recorra para encontrar el nodo y asígnelo al nodo.
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.
注意
: 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.