Para ser mais simples (tanto quanto eu poderia mais simples) + mais alguns detalhes.
Essas propriedades dependem de muitas coisas internas que seriam muito interessantes de entender - antes de passar para elas diretamente.
TREEIFY_THRESHOLD -> quando um único balde atinge isso (e o número total excede MIN_TREEIFY_CAPACITY
), ele é transformado em um nó de árvore vermelho / preto perfeitamente equilibrado . Por quê? Por causa da velocidade de pesquisa. Pense nisso de uma maneira diferente:
seriam necessárias no máximo 32 etapas para pesquisar uma entrada em um balde / compartimento com entradas Integer.MAX_VALUE .
Alguma introdução para o próximo tópico. Por que o número de caixas / baldes é sempre uma potência de dois ? Pelo menos dois motivos: mais rápido do que a operação do módulo e o módulo em números negativos será negativo. E você não pode colocar uma entrada em um balde "negativo":
int arrayIndex = hashCode % buckets; // will be negative
buckets[arrayIndex] = Entry; // obviously will fail
Em vez disso, há um bom truque usado em vez do módulo:
(n - 1) & hash // n is the number of bins, hash - is the hash function of the key
Isso é semanticamente o mesmo que operação de módulo. Ele manterá os bits mais baixos. Isso tem uma consequência interessante quando você faz:
Map<String, String> map = new HashMap<>();
No caso acima, a decisão de para onde vai uma entrada é tomada com base nos últimos 4 bits apenas do seu hashcode.
É aqui que a multiplicação dos baldes entra em jogo. Sob certas condições (levaria muito tempo para explicar com detalhes exatos ), os baldes dobram de tamanho. Por quê? Quando os baldes dobram de tamanho, há mais um bit entrando em ação .
Portanto, você tem 16 depósitos - os últimos 4 bits do hashcode decidem para onde vai uma entrada. Você dobra os baldes: 32 baldes - os 5 últimos bits decidem para onde irá a entrada.
Como tal, este processo é denominado re-hashing. Isso pode ficar lento. Isto é (para pessoas que se importam) porque HashMap é "brincado" como: rápido, rápido, rápido, lento . Existem outras implementações - pesquisar hashmap sem pausa ...
Agora UNTREEIFY_THRESHOLD entra em jogo após o re-hash. Nesse ponto, algumas entradas podem mover-se desses compartimentos para outros (eles adicionam mais um bit ao (n-1)&hash
cálculo - e, como tal, podem mover-se para outros depósitos) e podem chegar a isso UNTREEIFY_THRESHOLD
. Neste ponto, não vale a pena manter a lixeira como red-black tree node
, mas em LinkedList
vez disso, como
entry.next.next....
MIN_TREEIFY_CAPACITY é o número mínimo de depósitos antes que um determinado depósito seja transformado em uma árvore.
String
, têm um espaço de valor muito maior do que oint
código hash, portanto, as colisões são inevitáveis. Agora, depende dos valores reais, comoString
s reais , que você coloca no mapa, se você obtém uma distribuição uniforme ou não. Uma má distribuição pode ser resultado apenas de má sorte.