El conjunto en Java es un conjunto que no contiene elementos duplicados, o para ser precisos, un par de elementos que no contiene E1.Equals (E2). NULL está permitido en el set. El conjunto no puede garantizar el orden de los elementos en el conjunto.
Al agregar un elemento para establecer, si el elemento especificado no existe, la adición es exitosa. Es decir, si el elemento E1 no existe en el conjunto (E == nulo? E1 == NULL: E.Queals (E1)), entonces E1 se puede agregar al conjunto.
Aquí hay una clase de implementación establecida hashset como ejemplo, e introduce brevemente el principio de SET para no repetir la implementación:
paquete com.darren.test.overide; public class CustomString {private String Value; public CustomString () {this ("");} public CustomString (valor de cadena) {this.value = valor;}} paquete 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"); CustomString C = New CustomString ("B"); CustomString D = New String CustomString ("b"); system.out.println ("a.equals (b) ==" + a.equals (b)); system.out.println ("c.equals (d) ==" + c.equals (d)); set <object> set = nuevo set = nuevo Hashset <Sect> (); set.add (a); set.add (b); set.add (c); set.add (d); system.out.println ("set.size () ==" + set.size ()); para (objeto objeto: set) {system.out.println (objeto);}}}}}}Los resultados de la operación son los siguientes:
A.Equals (b) == True C.Equals (d) == false set.size () == 3 com.darren.test.overide.customstring@2c39d2 a com.darren.test.overide.customstring@5795ce
Tal vez hayas visto la llave, es correcta, es el método igual. Todavía es inapropiado decir esto, pero para ser preciso, deberían ser los métodos iguales y de hashcode. ¿Por qué dices eso? Cambiemos la clase personalizada y la probemos:
paquete com.darren.test.overide; public class CustomString {private String Value; public CustomString () {this ("");} public CustomString (String Value) {this.value = value;}@anular public boolean iguales (obj obj) {if (this == obj) {return real;} si (OBJ OBJ ENSISTESOF) {CustomString OBJ) {if (este == obj) {return real; obj; return CustomString.Value.equals (valor);} else {return false;}}}Resultados de la prueba:
A.Equals (b) == verdadero c.equals (d) == true set.size () == 3 com.darren.test.overide.customstring@12504e0 a com.darren.test.overide.customstring@1630eb6
El valor de retorno de igual este tiempo es verdadero, pero el tamaño del conjunto sigue siendo 3.
Sigamos cambiando
paquete com.darren.test.overide; public class CustomString {private String Value; public CustomString () {this ("");} public CustomString (valor de cadena) {this.value = valor;}@anular public int hashcode () {// return súper.hashcode (); regresar 1;}}Mire los resultados nuevamente:
A.Equals (b) == True C.Equals (d) == false set.size () == 3 com.darren.test.overide.customstring@1 com.darren.test.overide.customstring@1 a
Solo reescribir el método hashcode, no reescribir el método igual
Finalmente, cámbielo
paquete com.darren.test.overide; public class CustomString {private String Value; public CustomString () {this ("");} public CustomString (String Value) {this.value = value;}@anular public boolean iguales (obj obj) {if (this == obj) {return real;} si (OBJ OBJ ENSISTESOF) {CustomString OBJ) {if (este == obj) {return real; obj; return CustomString.Value.equals (valor);} else {return false;}}@anular public int hashcode () {// return super.hashcode (); regresar 1;}}Resultados finales:
A.Equals (b) == verdadero c.equals (d) == true set.size () == 2 com.darren.test.overide.customstring@1 a
Ok, se demuestra que necesita reescribir el método igual y el método hashcode, y ver el principio:
Convención para hashcode en java.lnag.object:
1. Durante la ejecución de una aplicación, si la información utilizada para comparar el método igual de un objeto no se modifica, el método hashcode se llama varias veces en el objeto y debe devolver constantemente el mismo entero.
2. Si los dos objetos son iguales de acuerdo con el método igual (Objeto), llamar al método hashcode de cualquiera de los dos objetos debe producir el mismo resultado entero.
3. Si los dos objetos no son iguales según el método igual (Objeto), entonces se llama el método hashcode de cualquiera de los dos objetos, y no se requieren resultados enteros diferentes. Pero si puede ser diferente, puede mejorar el rendimiento de la tabla hash.
En Hashset, las operaciones básicas son implementadas por la capa hashmap, porque la capa hashset usa hashmap para almacenar datos. Al agregar un elemento a un hashset, primero calcule el valor hashcode del elemento y luego use esto (el código hash del elemento)% (el tamaño de la colección hashmap) + 1 para calcular la ubicación de almacenamiento de este elemento. Si esta posición está vacía, agregue el elemento; Si no está vacío, use el método igual para comparar si los elementos son iguales y, si es igual, no lo agregue, de lo contrario, encuentre un espacio en blanco para agregarlo.
El siguiente es parte del código fuente de hashset:
paquete java.util; public class hashset <E> extiende AbstractSet <E> SET <E>, Clonable, java.io.Serializable {static final Long SerialVersionUid = -50247444067133321676l; // La capa subyacente utiliza hashmap para ahorrar todos los elementos en el hahset. Hashmap transitorio privado <e, objeto> map; // Definir un objeto virtual como el valor de hashmap, y defina este objeto como final estática. Objeto final estático privado presente = nuevo objeto ();/*** El constructor predeterminado sin parámetros construye un hashset vacío. * * De hecho, la capa subyacente inicializará un hashmap vacío y usará la capacidad inicial predeterminada de 16 y el factor de carga de 0.75. */public hashset () {map = new Hashmap <e, object> ();}/*** Construye un nuevo conjunto que contenga los elementos en la colección especificada. * * La capa subyacente real utiliza el factor de carga predeterminado 0.75 y es suficiente para contener la capacidad inicial de todos los elementos en la colección especificada * para crear un hashmap. * @param c Los elementos en él se almacenarán en la colección en este conjunto. */public hashset (colección <extiende e> c) {map = new Hashmap <e, object> (math.max ((int) (c.size ()/. 75f) + 1, 16)); addall (c);}/*** Construye un heta de hash vacío con la capacidad inicial especificada y el factor de carga. * * La capa subyacente real construye un hashmap vacío con los parámetros correspondientes. * @Param Capacidad inicial de Capacidad inicial. * @param LoadFactor Factor de carga. */public Hashset (int InitialCapacity, Float LoadFactor) {MAP = new Hashmap <e, objeto> (inicialCapacity, LoadFactor);}/*** Construya un hashset vacío con la capacidad inicial especificada. * * De hecho, la capa subyacente construye un hashmap vacío con los parámetros correspondientes y el factor de carga del factor de carga de 0.75. * @Param Capacidad inicial de Capacidad inicial. */public hashset (int InitialCapacity) {MAP = new Hashmap <e, objeto> (inicialcapacity);}/*** Construya una nueva colección de hash de enlace vacío con la capacidad inicial especificada y el factor de carga. * Este constructor es permiso de acceso al paquete y no está expuesto al público. En realidad es solo soporte para LinkedHashset. * * De hecho, la capa subyacente construirá una instancia vacía de LinkedHashMap con los parámetros especificados para implementarla. * @Param Capacidad inicial de Capacidad inicial. * @param LoadFactor Factor de carga. * @param etiqueta ficticia. */Hashset (int InitialCapacity, Float LoadFactor, Boolean Dummy) {MAP = new LinkedHashMap <e, Object> (InicialCapacity, LoadFactor);}/*** Devuelve el iterador que itera los elementos en este conjunto. El orden de los elementos de retorno no es específico. * * La capa subyacente en realidad llama a la tecla del hashmap subyacente para devolver todas las teclas. * Se pueden ver los elementos en el hashset, pero se almacenan en la clave del hashmap subyacente, y el valor se identifica mediante un objeto final estático. * @return iterator que itera sobre elementos en este conjunto. */@Anular public Iterator <E> iterator () {return map.KeySet (). Iterator ();}/*** Devuelve el número de elementos en este conjunto (la capacidad del conjunto). * * La capa subyacente realmente llama al método size () de hashmap para devolver el número de entrada, y obtiene el número de elementos en el conjunto. * @return el número de elementos en este conjunto (capacidad del conjunto). */@Anular public int size () {return map.size ();}/*** return true si este conjunto no contiene ningún elemento. * * La capa subyacente en realidad llama isEmpty () de hashmap para determinar si el hashset está vacío. * @return return true si este conjunto no contiene ningún elemento. */@Anular public boolean isEmpty () {return map.isEmpty ();}/*** return true si este conjunto contiene el elemento especificado. * Más específicamente, True se devuelve si y solo si este conjunto contiene un elemento E que satisface (O == NULL? E == NULL: O.Equals (e)) *. * * La tecla contenida de la llamada real subyacente a Hashmap determina si contiene la clave especificada. * @param o Se ha probado la existencia del elemento en este conjunto. * @return return true si este conjunto contiene el elemento especificado. */@Anular public boolean contiene (objeto o) {return map.containskey (o);}/*** Si el elemento especificado no está incluido en este conjunto, agregue el elemento especificado. * Más específicamente, si este conjunto no contiene elemento E2 que satisface (e == nulo? E2 == null: e.equals (e2)) *, el elemento especificado E se agrega a este conjunto. * Si este conjunto ya contiene el elemento, la llamada no cambia el conjunto y devuelve falso. * * La capa subyacente en realidad pondrá el elemento como una llave en el hashmap. * Dado que el método Put () de HashMap agrega un par de valores clave, cuando la clave en la nueva entrada de HashMap * es la misma que la clave de la entrada original en la colección (hashcode () devuelve igual, y también devuelve verdadero a través de la comparación igual), * El valor de la entrada recién agregada sobrescribirá el valor de la entrada original, pero la clave no cambiará ninguno. * Por lo tanto, si se agrega un elemento existente al hashset, el elemento de recolección recientemente agregado no se colocará en el hashmap, y * el elemento original no cambiará ninguno, lo que satisface la característica de la no repetición de elementos en el conjunto. * @param e elementos que se agregarán a este conjunto. * @return return true Si este conjunto no contiene el elemento especificado. */@Anular public boolean add (e e) {return map.put (e, presente) == null;}/*** Si el elemento especificado existe en este conjunto, se eliminará. * Más específicamente, si este conjunto contiene un elemento E que satisface (O == NULL? E == NULL: O.Equals (e)), * lo eliminará. Devuelve verdadero si este conjunto ya contiene el elemento (o: verdadero si este conjunto cambia debido a la llamada). (Una vez que la llamada regresa, este conjunto ya no contiene el elemento). * * La capa subyacente en realidad llama al método de eliminación de hashmap para eliminar la entrada especificada. * @param o Objeto que debe eliminarse si existe en este conjunto. * @return return true si el conjunto contiene el elemento especificado. */@Anular public boolean Remete (objeto o) {return map.remove (o) == presente;}/*** Elimine todos los elementos de este conjunto. Después de que esta llamada regrese, el conjunto estará vacío. * * La capa subyacente en realidad llama al método claro de hashmap para borrar todos los elementos en la entrada. */@Anular public void clear () {map.clear ();}}Resumir
Lo anterior es todo el contenido de este artículo sobre el análisis del principio de eliminación de valores duplicados. Espero que sea útil para todos. Los amigos interesados pueden continuar referiéndose a otros temas relacionados en este sitio. Si hay alguna deficiencia, deje un mensaje para señalarlo. ¡Gracias amigos por su apoyo para este sitio!