Reescribir código fuente del JDK: HashMap método de optimización de cambio de tamaño de reflexión

        Consejos: Este razonamiento no es exacto, porque en la mayoría de los casos los valores hash son diferentes elementos de la matriz en la misma posición en el HashMap , pero todo el proceso de pensamiento es completa, interesados pueden mirar.


No hablamos mucho, nos vemos directamente el método de cambio de tamaño HashMap Fuente:

Enfoque 715-744 línea, ordeno que conclusión, voy a utilizar esta línea de código para reemplazar los casi 30 líneas, de la siguiente manera:

newTab[e.hash & (newCap - 1)] = e;

Es probable que lo viste, y esto por encima de  e.next == operación nula después del juicio es el mismo, lo que puede determinar directamente fusionar estos dos , de un método de cambio de tamaño después reescrita como sigue:

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;
            }
            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);
        }
        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 (int j = 0; j < oldCap; ++j) {
                Node<K,V> e;
                if ((e = oldTab[j]) != null) {
                    oldTab[j] = null;
                    if (e instanceof TreeNode)
                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                    else { // preserve order
                       newTab[e.hash & (newCap - 1)] = e;
                    }
                }
            }
        }
        return newTab;
    }

  

Pensamiento analítico:

Analicemos lo que mi proceso de pensamiento, de hecho, lo primero que pensé es que esta versión de los siguientes:

if ((e.hash & oldCap) == 0) {
	newTab[j] = e;
}else {
	newTab[j+ oldCap]= e;
}

Se puede entonces sentirse mejor, existe la siguiente línea de código 2:

  newTab[e.hash & oldCap == 0?j:j+ oldCap] = e;

Podría haber estado aquí puede terminar, pero me di cuenta de repente que podría ser más concisa, de manera que la línea de código que comienza con, y la fuente de la línea 712 y, por lo que pueden fusionarse directamente.

Después me encontré con esta optimización es considerar el HashMap herencia de clases para controlar la prueba a prueba, pero el método no es cambiar el tamaño y las palabras clave pública modificado finales se modifica, debe haber copiado todo el código fuente HashMap, y luego modificar la validación del método de cambio de tamaño se puede realizar, creo que una molestia, pero no era necesario.

Así que aquí, entonces seré el pensamiento del autor original para verificar la exactitud de mi empuje inverso optimizado por cierto. Continuamos analizando las líneas 715-744 del método de código de cambio de tamaño, primero se define loHead, loTail y hiHead, hiTail estas cuatro variables, el propósito es distinguir (e.hash y oldCap) == 0 y (e.hash y oldCap)! = 0, este es el caso debido a que la expansión en el e.hash HashMap y 2n-1 sólo puede ser el valor de índice de la matriz original subíndice j índice o el subíndice de la matriz más la longitud del original la matriz original  j + oldCap . Pero, de hecho, no hay necesidad de definir cuatro variables, sólo es necesario definir dos cabeza y la cola lata. ¿Por qué? Ahora miramos el código nos centramos en do-while:

línea clave 721, se puede ver e.hash () y oldCap estas dos variables  do-while es constante, ya que e es la lista completa en la misma posición de la matriz original, ellos valores hash debe ser igual. Sobre la base de esta conclusión, podemos optimizar lo que él pensaba 715-744 líneas de código en el autor original, de la siguiente manera:

                        Node<K,V> head = null, tail = null;
                        Node<K,V> next;
                        do {
                            next = e.next;
                            if (tail == null)
                                head = e;
                            else
                                tail.next = e;
                            tail = e;
                        } while ((e = next) != null);
                        if (tail != null) {
                            tail.next = null;
                            newTab[(head.hash & oldCap) == 0?j:j+ oldCap] =  head;
                        }

Sólo la cabeza y de la cola 2 variables para completar la función original. Escribió aquí, creo que usted probablemente sabe, el análisis anterior del código se puede ver, de hecho, la cabeza y la cola variable y de poca utilidad práctica. Después del final de la do-while , primero determinar si la cola está vacía, esta línea no no es completamente necesario, ya que se ha determinado en la línea e 588 es nulo, los siguientes:

Así que después de entrar en la cola de bucle sin duda se vacía, a continuación, utilizar el valor hash oldCap la cabeza de la broca después de la operación para obtener la posición de índice de la matriz, se dirigirá a la nueva matriz, esta línea es simplemente superflua, porque la cabeza = única e cuando el primer ciclo de la tarea, no es necesario que el conjunto do-while, directamente reemplazar la cabeza con el correo no está en cuestión, después de esto ha sido sustituido por la línea e de código que estoy empezando optimización:

newTab[(e.hash & oldCap) == 0?j:j+ oldCap] = e;

Ya que se encuentra a continuación, valor fijo e.hash, no hay necesidad de ternarias expresiones, directamente e.hash y (Newcap - 1) para dar el índice subíndice en la línea:

 newTab[e.hash & (newCap - 1)] = e;

Así que pensamos que lanzamos el autor original de este código optimizado.

resumen:

Vi por primera vez la línea de este código 715-744 es algo incomprensible, siempre se siente un poco incómodo, después de leerlo de nuevo, llego a la conclusión de que newtab [j] = e;

Así que después de pensamiento y análisis después de esta línea ha sido optimizado código:

 newTab[e.hash & (newCap - 1)] = e;

También en el código fuente se puede sentir un poco llamativo, demasiado amplia. De hecho, miramos hacia atrás y pensamos, encontrará todo el propósito de la línea original 715-744 se copia en la lista del orden de la matriz a la nueva matriz para evitar jdk1.7 bucle infinito en la expansión del tiempo de migración de datos, en realidad es muy simple puede hacer el

Si los estudiantes tienen un problema, puede salir en el dedo medio comentarios

Publicado 25 artículos originales · ganado elogios 51 · Vistas a 20000 +

Supongo que te gusta

Origin blog.csdn.net/Royal_lr/article/details/103196010
Recomendado
Clasificación