Detalhe de implementação do método de redimensionamento do HashMap

Como o título sugere, essa é uma pergunta sobre um detalhe de implementação doHashMap#resize - é quando a matriz interna é dobrada em tamanho. É um pouco prolixo, mas eu realmente tentei provar que entendi melhor ...

Isso acontece em um momento em que as entradas neste depósito / compartimento específico são armazenadas em umLinked moda - tendo, assim, uma ordem exata e no contexto da perguntaIsso é importante.

Geralmente oresize pode ser chamado de outros lugares também, mas vamos ver apenas este caso.

Suponha que você coloque essas strings como chaves em umHashMap (à direita, há ohashcode depois de HashMap#hash - esse é o re-hash interno.) Sim, eles são cuidadosamente gerados, não aleatórios.

 DFHXR - 11111
 YSXFJ - 01111 
 TUDDY - 11111 
 AXVUH - 01111 
 RUTWZ - 11111
 DEDUC - 01111
 WFCVW - 11111
 ZETCU - 01111
 GCVUR - 11111 

Há um padrão simples a ser observado aqui - os últimos 4 bits são iguais para todos eles - o que significa que quando inserimos 8 dessas chaves (são 9 no total), elas terminam no mesmo balde; e no dia 9HashMap#put, aresize será chamado.

Portanto, se atualmente houver 8 entradas (com uma das teclas acima) noHashMap - significa que existem 16 buckets neste mapa e os últimos 4 bits da chave decidiram onde as entradas terminam.

Colocamos a chave nove. Neste pontoTREEIFY_THRESHOLD é atingido eresize é chamado. Os compartimentos são dobrados para32 e mais um bit das chaves decide para onde essa entrada irá (então, 5 bits agora).

Por fim, esse trecho de código é alcançado (quandoresize acontece):

 Node<K,V> loHead = null, loTail = null;
 Node<K,V> hiHead = null, hiTail = null;
 Node<K,V> 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;
     }
 } while ((e = next) != null);



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

Na verdade, não é tão complicado ... o que faz, divide o compartimento atual em entradas quemoverá para outras posições e entradas quenão vai se mover para outras caixas - mas permanecerá nessa com certeza.

E é realmente muito inteligente como isso acontece - é através deste código:

 if ((e.hash & oldCap) == 0) 

O que isso faz é verificar se o próximo bit (o quinto no nosso caso) é realmente zero - se for, significa que essa entrada permanecerá onde está; caso contrário, ele se moverá com uma potência de dois desvios na nova lixeira.

E agora, finalmente, a pergunta: esse trecho de código no redimensionamento é feito com cuidado para quepreserva a ordem das entradas havia nessa lixeira.

Então, depois de colocar essas 9 teclas noHashMap o pedido será:

DFHXR -> TUDDY -> RUTWZ -> WFCVW -> GCVUR (one bin)

YSXFJ -> AXVUH -> DEDUC -> ZETCU (another bin)

Por que você deseja preservar a ordem de algumas entradas noHashMap. Ordem em umMap érealmente ruim como detalhadoaqui ouaqui.

questionAnswers(2)

yourAnswerToTheQuestion