Sobre o HashCode, na Wikipedia:
Na linguagem de programação Java, toda classe fornece implicitamente ou explicitamente um método hashcode (), que digere os dados armazenados em uma instância da classe em um único valor de hash (um número inteiro assinado de 32 bits).
O HashCode extrai um número inteiro de 32 bits com base em todos os dados armazenados em uma instância de objeto. O objetivo desse número inteiro é indicar a singularidade da instância. É um pouco semelhante ao código MD5 e cada arquivo pode gerar um código MD5 exclusivo através do algoritmo MD5. No entanto, o HashCode em Java não implementa realmente o código de hash para gerar um código de hash exclusivo para cada objeto, e ainda há uma certa chance de duplicação.
Vamos dar uma olhada na classe de objeto primeiro. Sabemos que a classe de objeto é a classe pai direta ou indireta de todas as classes em um programa Java e está no ponto mais alto do nível de classe. Muitos métodos comuns são definidos na classe de objeto, incluindo o método HashCode sobre o qual queremos falar, como segue
Public Final Native Class <?> getClass (); public nativo int hashcode (); public boolean é igual (objeto obj) {return (this == obj); } public string tostring () {return getClass (). getName () + "@" + inteiro.tohexstring (hashcode ()); }Observe que existe um modificador nativo na frente do método HashCode, o que significa que o método HashCode é implementado em um idioma não Java. O método específico é implementado externamente e retorna o endereço do objeto de memória.
Em muitas classes de Java, os métodos iguais e hashcode são reescritos. Por que isso? A classe de string mais comum, como se eu definir duas cordas com os mesmos caracteres, então ao compará -los, o resultado que eu quero deve ser igual. Se você não substituir os métodos iguais e hashcode, eles definitivamente não serão iguais, porque os endereços de memória dos dois objetos são diferentes.
public int hashCode () {int h = hash; if (h == 0) {int off = offset; char val [] = valor; int len = count; for (int i = 0; i <len; i ++) {h = 31*h+val [off ++]; } hash = h; } retornar h; }De fato, este código é a implementação desta expressão matemática
s [0]*31^(n-1) + s [1]*31^(n-2) +… + s [n-1]
S [i] é o i-ésimo caractere de uma corda e n é o comprimento de uma corda. Então, por que usar 31 aqui em vez de outros números? O Java eficaz diz o seguinte: a razão pela qual 31 é escolhida é porque é um número primo estranho. Se o multiplicador for um número par e a multiplicação transborda, as informações serão perdidas, porque multiplicar com 2 é equivalente à operação de mudança. Os benefícios do uso de números primos não são óbvios, mas os resultados de hash são usados convencionalmente para calcular os resultados do hash. 31 tem um bom recurso, que é usar turno e subtração em vez de multiplicação para obter melhor desempenho: 31*i == (i << 5) -i. As VMs podem concluir automaticamente essa otimização.
Como você pode ver, a classe String usa seu valor de valor como um parâmetro para calcular o HashCode, ou seja, o mesmo valor definitivamente terá o mesmo valor de hashcode. Isso também é fácil de entender, porque os valores do valor são iguais; portanto, se a comparação igual a igual, o método igual é igual, o código de hash deverá ser igual. O contrário não é necessariamente verdadeiro. Não garante que o mesmo hashcode deve ter o mesmo objeto.
Uma boa função de hash deve ser assim: produzir códigos de hash desiguais para diferentes objetos.
Em casos ideais, a função de hash deve distribuir uniformemente instâncias desiguais no conjunto para todos os códigos de hash possíveis. É muito difícil alcançar essa situação ideal, pelo menos Java não a alcançou. Porque podemos ver que o HashCode é gerado não aleatoriamente e possui certas regras, que é a equação matemática acima. Podemos construir alguns que têm o mesmo hashcode, mas valores de valor diferentes, por exemplo: o código de hash de AA e BB são os mesmos.
O seguinte código:
classe pública principal {public static void main (string [] args) {main m = new main (); System.out.println (m); System.out.println (Integer.toHexString (M.HashCode ())); String a = "aa"; String b = "bb"; System.out.println (a.hashcode ()); System.out.println (b.hashcode ()); }}Resultado da saída:
Principal@2a139a55 2a139a55 2112 2112
Geralmente, ao reescrever a função igual, você também precisa reescrever a função HashCode. Por que isso?
Vamos dar uma olhada neste exemplo, vamos criar um funcionário simples de classe
Public Classe Funcionário {ID inteiro privado; String privada primeiro nome; string privada stringname; Departamento de String Privado; public integer getId () {return id; } public void SetId (ID inteiro) {this.id = id; } public String getFirstName () {return FirstName; } public void setFirstName (String FirstName) {this.firstName = FirstName; } public string getLastName () {return lastName; } public void setLastName (string lastName) {this.LastName = lastName; } public string getDepartment () {departamento de retorno; } public void setDepartment (departamento de string) {this.department = departamento; }}A classe de funcionários acima possui apenas algumas propriedades e getters e setters muito básicos. Agora considere uma situação em que você precisa comparar dois funcionários.
classe pública Equalstest {public static void main (string [] args) {funcionário e1 = new funcionário (); Funcionário e2 = new funcionário (); e1.setId (100); e2.SetId (100); // imprime False no console System.out.println (e1.equals (e2)); }}Não há dúvida de que o programa acima produzirá falso, mas, de fato, os dois objetos acima representam através de um funcionário. A verdadeira lógica de negócios espera que retornemos verdadeiro.
Para conseguir isso, precisamos reescrever o método igual.
public boolean é igual (objeto o) {if (o == null) {return false; } if (o == this) {return true; } if (getClass ()! = O.getClass ()) {return false; } Funcionário e = (funcionário) o; return (this.getId () == e.getId ());} Adicione esse método à classe acima e o EAUQLSTEST produzirá true.
Então, terminamos? Não, vamos mudar o método de teste e dar uma olhada.
importar java.util.hashset; importar java.util.set; public class Equalstest {public static void main (string [] args) {funcionário e1 = new funcionário (); funcionário e2 = new funcionário ();); e1.PrintLN (100); E2.Setid (100); // Prints '); HASHSET <EGRIGADO> (); funcionários.add (e1); funcionários.O programa acima gera dois resultados. Se os dois objetos do funcionário forem iguais, retorne a verdade, apenas um objeto deve ser armazenado no conjunto. Qual é o problema?
Esquecemos o segundo método importante HashCode (). Assim como Javadoc, do JDK, disse, se você reescrever o método iguals (), você deverá reescrever o método hashcode (). Vamos adicionar o método a seguir e o programa será executado corretamente.
@Override public int hashCode () {final int prime = 31; int resultado = 1; resultado = prime * resultado + getId (); resultado de retorno; }Coisas para lembrar
Tente garantir que a mesma propriedade do objeto seja usada para gerar dois métodos: hashcode () e iguals (). No nosso caso, usamos IDs de funcionários.
O método eqauls deve ser consistente (se o objeto não for modificado, iguais deverão retornar o mesmo valor)
A qualquer momento, enquanto A.Equals (B), A.HashCode () deve ser igual a B.HashCode ().
Ambos devem ser reescritos ao mesmo tempo.
Resumir
O exposto acima é tudo sobre o profundo entendimento deste artigo do método HashCode em Java, e espero que seja útil para todos. Amigos interessados podem continuar se referindo a outros tópicos relacionados neste site. Se houver alguma falha, deixe uma mensagem para apontá -la. Obrigado amigos pelo seu apoio para este site!