Definido em Java é um conjunto que não contém elementos duplicados ou, para ser preciso, um par de elementos que não contém E1.Equals (E2). nulo é permitido no conjunto. O conjunto não pode garantir a ordem dos elementos no conjunto.
Ao adicionar um elemento para definir, se o elemento especificado não existir, a adição será bem -sucedida. Ou seja, se o elemento E1 não existir no conjunto (e == null? E1 == NULL: E.Queals (e1)), o E1 poderá ser adicionado ao conjunto.
Aqui está uma classe de implementação definida hashset como exemplo e apresente brevemente o princípio do conjunto para não repetir a implementação:
pacote com.darren.test.overide; public class CustomString {private String value; public CustomString () {this ("");} public CustomString (String value) {this.value = value;}}} pacote com.darren.test.overide; importar java.util.hashset; importar java.util.set; public class HashSetTest {public static void main (string [] args) {string a = new string ("a"); string b = new string "a"); CustomString ("b"); System.out.println ("A.Equals (b) ==" + A.Equals (b)); System.out.println ("C.Equals (d) ==" + c.Equals (d)); set <ject> set = novo HASHSET <BECT> (); set.add (a); set.add (b); set.add (c); set.add (d); system.out.println ("set.size () ==" + set.size ()); para (objeto: set) {System.out.println (object);};Os resultados da operação são os seguintes:
A.Equals (b) == Verdadeiro C.Equals (d) == false set.size () == 3 com.darren.test.overide.customstring@2c39d2 a com.darren.test.overide.customstring@5795ce
Talvez você tenha visto a chave, isso mesmo, é o método igual. Ainda é inapropriado dizer isso, mas, para ser preciso, deve ser os métodos iguais e hashcode. Por que você diz isso? Vamos mudar a classe CustomString e testá -la:
pacote com.darren.test.overide; public class CustomString {private string value; public CustomString () {this ("");} public CustomString (String value) {this.value = value;}@substituição pública; obj; return customString.value.equals (value);} else {return false;}}}Resultados do teste:
A.Equals (b) == Verdadeiro C.Equals (d) == true set.size () == 3 com.darren.test.overide.customstring@12504e0 a com.darren.test.overide.customstring@1630Eb6
O valor de retorno dos iguais desta vez é verdadeiro, mas o tamanho do conjunto ainda é 3.
Vamos continuar a mudar
pacote com.darren.test.overide; public class CustomString {private string value; public CustomString () {this ("");} public CustomString (String value) {this.value = value;}@substituir public int hashCode () {// retornar super.hashcode (); retornar 1;}}Veja os resultados novamente:
A.Equals (b) == Verdadeiro C.Equals (d) == false set.size () == 3 com.darren.test.overide.customstring@1 com.darren.test.overide.customstring@1 a
Reescrever apenas o método HashCode, não reescrever o método igual
Finalmente, mude
pacote com.darren.test.overide; public class CustomString {private string value; public CustomString () {this ("");} public CustomString (String value) {this.value = value;}@substituição pública; obj; return customString.value.equals (value);} else {return false;}}@substituir public int hashCode () {// return super.hashcode (); retornar 1;}}Resultados finais:
A.Equals (b) == True C.Equals (d) == true set.size () == 2 com.darren.test.overide.customstring@1 a
Ok, está provado que você precisa reescrever o método Equals e HashCode e ver o princípio:
Convenção para Hashcode em java.lnag.object:
1. Durante uma execução de aplicação, se as informações usadas para comparar o método igual de um objeto não forem modificadas, o método HashCode é chamado várias vezes no objeto e deve retornar consistentemente o mesmo número inteiro.
2. Se os dois objetos forem iguais de acordo com o método Equals (Objecto), chamando o método HashCode de qualquer um dos dois objetos deve produzir o mesmo resultado inteiro.
3. Se os dois objetos não forem iguais de acordo com o método igual (ObjectO), o método HashCode de qualquer um dos dois objetos é chamado e não são necessários resultados inteiros diferentes. Mas se puder ser diferente, pode melhorar o desempenho da tabela de hash.
No hashset, as operações básicas são implementadas pela camada de hashmap, porque a camada de hashset usa o hashmap para armazenar dados. Ao adicionar um elemento a um hashset, calcule primeiro o valor de hashcode do elemento e depois use isso (o código de hash do elemento)% (o tamanho da coleção hashmap) + 1 para calcular o local de armazenamento desse elemento. Se esta posição estiver vazia, adicione o elemento; Se não estiver vazio, use o método Equals para comparar se os elementos são iguais e, se forem iguais, não o adicione, caso contrário, encontre um espaço em branco para adicioná -lo.
A seguir, faz parte do código -fonte do hashset:
pacote java.util; a classe pública Hashset <E> estende o abstractSet <e> implementos conjunto <e>, clonável, java.io.Serializable {estático final serialversionuid = -5024744406713321676 //Ter usa a camada subjacente. HashMap transitório privado <e, objeto> map; // define um objeto virtual como o valor do hashmap e define esse objeto como final estático. Objeto final estático privado presente = new Object ();/*** O construtor sem parâmetros padrão constrói um hashset vazio. * * De fato, a camada subjacente inicializará um hash de hash vazio e usará a capacidade inicial padrão de 16 e o fator de carregamento de 0,75. */public hashSet () {map = new Hashmap <e, object> ();}/*** Construa um novo conjunto contendo os elementos na coleção especificada. * * A camada subjacente real usa o fator de carga padrão 0,75 e é suficiente para conter a capacidade inicial de todos os elementos na coleção * especificada para criar um hashmap. * @param c Os elementos nele serão armazenados na coleção neste conjunto. */Hashset público (coleção <estende e> c) {map = new Hashmap <e, object> (Math.max ((int) (c.size ()/. 75f) + 1, 16)); addall (c);}/*** Construa um hashset vazio com a capacidade inicial especificada e o fábrica de carga. * * A camada subjacente real constrói um hash de hash vazio com os parâmetros correspondentes. * @param InitialCapacity Capacidade inicial. * @Param LoadFactor Load Factor. */Public HashSet (int InitialCapacity, Float LoadFactor) {map = new Hashmap <e, objeto> (InitialCapacidade, LoadFactor);}/*** Construa um hashset vazio com a capacidade inicial especificada. * * De fato, a camada subjacente constrói um hash de hash vazio com os parâmetros correspondentes e o fator de carga do fator de carga de 0,75. * @param InitialCapacity Capacidade inicial. */Public HashSet (int InitialCapacity) {map = new Hashmap <e, object> (InitialCapacidade);}/*** Construa uma nova coleção de hash de link vazia com a capacidade inicial especificada e o LoadFactor. * Este construtor é permissão de acesso ao pacote e não está exposto ao público. Na verdade, é apenas suporte para o LinkedHashSet. * * De fato, a camada subjacente construirá uma instância vazia do LinkedHashMap com os parâmetros especificados para implementá -la. * @param InitialCapacity Capacidade inicial. * @Param LoadFactor Load Factor. * @param tag dummy. */HashSet (int InitialCapacity, Float LoadFactor, boolean Dummy) {map = new LinkedHashMap <e, object> (InitialCapacity, LoadFactor);}/*** Retorna o iterador que itera os elementos deste conjunto. A ordem dos elementos de retorno não é específica. * * A camada subjacente realmente chama o tecla do hashmap subjacente para retornar todas as teclas. * Os elementos no hashset podem ser vistos, mas são armazenados na chave do hashmap subjacente, e o valor é identificado por um objeto final estático. * @return iterator que itera sobre elementos neste conjunto. */@Substitua public iterator <e> iterator () {return map.keyset (). Iterator ();}/*** retorna o número de elementos neste conjunto (a capacidade do conjunto). * * A camada subjacente realmente chama o método size () do hashmap para retornar o número de entrada e obtém o número de elementos no conjunto. * @RETURN O número de elementos neste conjunto (capacidade do conjunto). */@Substitua public int size () {return map.size ();}/*** retorna true se esse conjunto não contiver nenhum elemento. * * A camada subjacente realmente chama isEmpty () do hashmap para determinar se o hashset está vazio. * @return retorna true se este conjunto não contiver nenhum elemento. */@Substitua public boolean isEmpty () {return map.isEmpty ();}/*** Retorne true se esse conjunto contiver o elemento especificado. * Mais especificamente, True é retornado se e somente se esse conjunto contiver um elemento E que satisfaz (o == null? E == null: O.Equals (e)) *. * * O ContansKey da chamada real subjacente ao hashmap determina se ele contém a chave especificada. * @param o A existência do elemento neste conjunto foi testada. * @return return true se este conjunto contiver o elemento especificado. */@Substitua public boolean contém (objeto o) {return map.containsKey (o);}/*** Se o elemento especificado não estiver incluído neste conjunto, adicione o elemento especificado. * Mais especificamente, se esse conjunto não contiver elemento E2 que satisfaça (e == null? E2 == NULL: E.Equals (e2)) *, o elemento especificado e é adicionado a esse conjunto. * Se esse conjunto já contiver o elemento, a chamada não altera o conjunto e retorna falsa. * * A camada subjacente realmente colocará o elemento como uma chave no hashmap. * Como o método put () do Hashmap adiciona um par de valores-chave, quando a chave na nova entrada do hashmap * é a mesma que a chave da entrada original na coleção (hashcode () retorna igual e também retorna o valor da entrada igual), o valor da entrada recorde. * Portanto, se um elemento existente for adicionado ao hashset, o elemento de coleta recém-adicionado não será colocado no hashmap e * o elemento original não alterará nenhum, o que satisfaz o recurso da não repetição de elementos no conjunto. * @param e elementos que serão adicionados a este conjunto. * @return retorna true se este conjunto não contiver o elemento especificado. */@Substitua public boolean add (e e) {return map.put (e, presente) == null;}/*** Se o elemento especificado existir neste conjunto, ele será removido. * Mais especificamente, se esse conjunto contiver um elemento E que satisfaz (o == null? E == NULL: O.Equals (e)), * o removerá. Retorne true se esse conjunto já contiver o elemento (ou: true se esse conjunto mudar devido à chamada). (Depois que a chamada retorna, esse conjunto não contém mais o elemento). * * A camada subjacente realmente chama o método de remoção de hashmap para excluir a entrada especificada. * @param o objeto que precisa ser removido se houver neste conjunto. * @return return true se definido contém o elemento especificado. */@Substitua public boolean Remover (objeto o) {retornar map.remove (o) == presente;}/*** Remova todos os elementos deste conjunto. Após essa chamada retornar, o conjunto estará vazio. * * A camada subjacente realmente chama o método claro de hashmap para limpar todos os elementos na entrada. */@Substituir public void clear () {map.clear ();}}Resumir
O exposto acima é todo o conteúdo deste artigo sobre a análise do princípio da remoção de hashset de valores duplicados. 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!