Défini dans Java est un ensemble qui ne contient pas d'éléments en double, ou pour être précis, une paire d'éléments qui ne contient pas e1.equals (E2). Null est autorisé dans le jeu. L'ensemble ne peut garantir l'ordre des éléments de l'ensemble.
Lors de l'ajout d'un élément à définir, si l'élément spécifié n'existe pas, l'ajout est réussi. Autrement dit, si l'élément e1 n'existe pas dans l'ensemble (e == null? E1 == null: e.queals (e1)), alors e1 peut être ajouté à l'ensemble.
Voici un HashSet de classe d'implémentation définie comme exemple, et introduire brièvement le principe de SET pour ne pas répéter l'implémentation:
package com.darren.test.overide; public class CustomString {private String Value; public CustomString () {this ("");} public CustomString (string value) {this.value = value;}} package com.darren.test.overide; import java.util.hashset; import java.util.set; public class hashsetTest {public static void main (String [] args) {string a = new String ("a"); string b = new String ("a"); coustomString c = new Custriel ("b"); CustomString d = new CustomString ("B"); System.out.println ("A.equals (b) ==" + a.equals (b)); System.out.println ("c.equals (d) ==" + c.equals (d)); set <objet> set = new HashSet <Bject> (); set.add (a); set.add (b); set.add (c); set.add (d); system.out.println ("set.size () ==" + set.size ()); pour (objet objet: set) {system.out.println (objet);}}}Les résultats de l'opération sont les suivants:
a.equals (b) == true c.equals (d) == false set.size () == 3 com.darren.test.overide.customstring@2c39d2 a com.darren.test.overide.customstring@5795cece
Peut-être que vous avez vu la clé, c'est vrai, c'est la méthode égale. Il est toujours inapproprié de le dire, mais pour être précis, ce devrait être les méthodes égales et codées de hash. Pourquoi dites-vous cela? Changeons la classe CustomString et le testons:
package com.darren.test.overide; public class CustomString {private String Value; public CustomString () {this ("");} public CustomString (string value) {this.value = value;} @ override public boolean égaux (objet obj) {if (this == obj) {return true;} else if (obj instancesthit obj; return customString.value.equals (valeur);} else {return false;}}}Résultats des tests:
a.equals (b) == true c.equals (d) == true set.size () == 3 com.darren.test.overide.customstring@12504e0 a com.darren.test.overide.customstring@1630eb6
La valeur de retour de l'égalité de cette fois est vraie, mais la taille de l'ensemble est toujours 3.
Continuons à changer
package com.darren.test.overide; public class CustomString {private String Value; public CustomString () {this ("");} public CustomString (string value) {this.value = value;} @ override public int hashcode () {// return super.hashcode (); retour 1;}}Regardez à nouveau les résultats:
a.equals (b) == true c.equals (d) == false set.size () == 3 com.darren.test.overide.customstring@1 com.darren.test.overide.customstring@1 a
Réécrivez uniquement la méthode HashCode, et non la réécriture de la méthode égale
Enfin, changez-le
package com.darren.test.overide; public class CustomString {private String Value; public CustomString () {this ("");} public CustomString (string value) {this.value = value;} @ override public boolean égaux (objet obj) {if (this == obj) {return true;} else if (obj instancesthit obj; return customString.value.equals (valeur);} else {return false;}} @ override public int hashcode () {// return super.hashcode (); retour 1;}}Résultats finaux:
a.equals (b) == true c.equals (d) == true set.size () == 2 com.darren.test.overide.customstring@1 a
Ok, il est prouvé que vous devez réécrire la méthode Equals et HashCode, et voir le principe:
Convention pour HashCode dans java.lnag.object:
1. Lors d'une exécution d'application, si les informations utilisées pour comparer la méthode égale d'un objet ne sont pas modifiées, la méthode HashCode est appelée plusieurs fois sur l'objet et il doit toujours renvoyer le même entier.
2. Si les deux objets sont égaux en fonction de la méthode Equals (Objecto), l'appel de la méthode HashCode de l'un ou l'autre des deux objets doit produire le même résultat entier.
3. Si les deux objets ne sont pas égaux en fonction de la méthode Equals (Objecto), la méthode HashCode de l'un ou l'autre des deux objets est appelée, et aucun résultat entier différent n'est requis. Mais si cela peut être différent, cela peut améliorer les performances de la table de hachage.
Dans HashSet, les opérations de base sont implémentées par la couche HashMap, car la couche HashSet utilise HashMap pour stocker les données. Lors de l'ajout d'un élément à un hashset, calculez d'abord la valeur de code de hash-code de l'élément, puis utilisez-le (le code de hash de l'élément)% (la taille de la collection de hashmap) + 1 pour calculer l'emplacement de stockage de cet élément. Si cette position est vide, ajoutez l'élément; S'il n'est pas vide, utilisez la méthode équivalente pour comparer si les éléments sont égaux, et si les égaux sont égaux, ne l'ajoutez pas, sinon trouverez un espace vide pour l'ajouter.
Ce qui suit fait partie du code source de Hashset:
package java.util; classe publique HashSet <e> étend AbstractSet <e> implémente Set <e>, Clonable, java.io.serializable {static final SerialVersionUID = -502474406713321676l; // La couche sous-jacente utilise un hashmap pour sauver tous les éléments dans le Soupon. Private Transient Hashmap <e, Object> Map; // Définir un objet virtuel comme la valeur de HashMap, et définir cet objet comme finale statique. Objet final statique privé présent = nouveau objet (); / ** * Le constructeur sans paramètre par défaut construit un hashset vide. * * En fait, la couche sous-jacente initialisera un hashmap vide et utilisera la capacité initiale par défaut de 16 et le facteur de charge de 0,75. * / public hashset () {map = new hashmap <e, objet> ();} / ** * construire un nouvel ensemble contenant les éléments de la collection spécifiée. * * La couche réelle sous-jacente utilise le facteur de charge par défaut 0,75 et est suffisante pour contenir la capacité initiale de tous les éléments de la collection * spécifiée pour créer un hashmap. * @param c Les éléments seront stockés dans la collection dans cet ensemble. * / public hashset (collection <étend e> c) {map = new hashmap <e, objet> (math.max ((int) (c.size () /. 75f) + 1, 16)); addall (c);} / ** * construire un hashset vide avec la capacité initiale spécifiée et la charge de charge. * * La couche réelle sous-jacente construit un hashmap vide avec des paramètres correspondants. * @Param InitialCapacity Capacité initiale. * @Param LoadFactor Facteur de charge. * / public hashset (int initialCapacity, float loshfactor) {map = new hashmap <e, objet> (initialCapacity, loadFactor);} / ** * construire un hashset vide avec la capacité initiale spécifiée. * * En fait, la couche sous-jacente construit un hashmap vide avec les paramètres correspondants et le facteur de charge de charge de 0,75. * @Param InitialCapacity Capacité initiale. * / public hashSet (int initialCapacity) {map = new hashmap <e, objet> (initialCapacity);} / ** * construire une nouvelle collection de hachage de liaison vide avec la Capacité initiale spécifiée et le chargement de chargement. * Ce constructeur est l'autorisation d'accès à package et n'est pas exposé au public. Il ne s'agit en fait que de la prise en charge de LinkedHashSet. * * En fait, la couche sous-jacente construira une instance vide LinkedHashMap avec les paramètres spécifiés pour l'implémenter. * @Param InitialCapacity Capacité initiale. * @Param LoadFactor Facteur de charge. * @param tag dummy. * / HashSet (int initialCapacity, float loadfactor, booléen mandem) {map = new LinkedHashmap <e, objet> (initialCapacity, loadFactor);} / ** * renvoie l'itérateur qui itère les éléments de cet ensemble. L'ordre des éléments de retour n'est pas spécifique. * * La couche sous-jacente appelle en fait le clés du hashmap sous-jacent pour retourner toutes les clés. * Les éléments du hashset peuvent être vus, mais sont stockés sur la clé du hashmap sous-jacent, et la valeur est identifiée par un objet final statique. * @return iterator qui itère sur les éléments de cet ensemble. * / @ Override public iterator <e> iterator () {return map.keyset (). Iterator ();} / ** * renvoie le nombre d'éléments dans cet ensemble (la capacité de l'ensemble). * * La couche sous-jacente appelle en fait la méthode size () de hashmap pour renvoyer le nombre d'entrée et obtient le nombre d'éléments dans l'ensemble. * @return le nombre d'éléments dans cet ensemble (capacité de l'ensemble). * / @ Override public int size () {return map.size ();} / ** * return true si cet ensemble ne contient aucun éléments. * * La couche sous-jacente appelle en fait iSempty () de hashmap pour déterminer si le hashset est vide. * @return Renvoie True si cet ensemble ne contient aucun éléments. * / @ Override public boolean isEmpty () {return map.isempty ();} / ** * return true si cet ensemble contient l'élément spécifié. * Plus spécifiquement, le vrai est renvoyé si et seulement si cet ensemble contient un élément e qui satisfait (o == null? E == null: o.equals (e)) *. * * Le CONTAINSKEY de l'appel réel sous-jacent à Hashmap détermine s'il contient la clé spécifiée. * @param o L'existence de l'élément dans cet ensemble a été testée. * @return return True si cet ensemble contient l'élément spécifié. * / @ Override public boolean contient (objet o) {return map.containsKey (o);} / ** * Si l'élément spécifié n'est pas inclus dans cet ensemble, ajoutez l'élément spécifié. * Plus spécifiquement, si cet ensemble ne contient pas l'élément e2 qui satisfait (e == null? E2 == null: e.equals (e2)) *, l'élément spécifié E est ajouté à cet ensemble. * Si cet ensemble contient déjà l'élément, l'appel ne modifie pas l'ensemble et renvoie faux. * * La couche sous-jacente mettra en fait l'élément en tant que clé dans le hashmap. * Étant donné que la méthode Put () de HashMap ajoute une paire de valeurs de clé, lorsque la clé de la nouvelle entrée du hashmap * est la même que la clé de l'entrée d'origine de la collection (HashCode () renvoie égale, et il renvoie également vrai par rapport à la comparaison égaux), * La valeur de la nouvelle entrée ajoutera l'écrasement de la valeur de l'entrée d'origine, mais la clé ne changera pas. * Par conséquent, si un élément existant est ajouté au hashset, l'élément de collecte nouvellement ajouté ne sera pas placé dans le hashmap, et * l'élément d'origine ne changera aucun, ce qui satisfait la fonctionnalité de non-répétition des éléments dans l'ensemble. * @param e éléments qui seront ajoutés à cet ensemble. * @return return True si cet ensemble ne contient pas l'élément spécifié. * / @ Override public booléen add (e e) {return map.put (e, présent) == null;} / ** * Si l'élément spécifié existe dans cet ensemble, il sera supprimé. * Plus spécifiquement, si cet ensemble contient un élément e qui satisfait (o == null? E == null: o.equals (e)), * le supprimera. Return true si cet ensemble contient déjà l'élément (ou: true si cet ensemble change en raison de l'appel). (Une fois l'appel renvoyé, cet ensemble ne contient plus l'élément). * * La couche sous-jacente appelle en fait la méthode de suppression de HashMap pour supprimer l'entrée spécifiée. * @param o Objet qui doit être supprimé s'il existe dans cet ensemble. * @return return true si SET contient l'élément spécifié. * / @ Override public booléen retire (objet o) {return map.remove (o) == présent;} / ** * supprimer tous les éléments de cet ensemble. Une fois cet appel renvoyé, l'ensemble sera vide. * * La couche sous-jacente appelle en fait la méthode claire de Hashmap pour effacer tous les éléments de l'entrée. * / @ Override public void clear () {map.clear ();}}Résumer
Ce qui précède est tout le contenu de cet article sur l'analyse du principe de l'élimination du hashset des valeurs en double. J'espère que ce sera utile à tout le monde. Les amis intéressés peuvent continuer à se référer à d'autres sujets connexes sur ce site. S'il y a des lacunes, veuillez laisser un message pour le signaler. Merci vos amis pour votre soutien pour ce site!