¿Agregar un valor duplicado a un HashSet / HashMap reemplaza el valor anterior?

137

Considere el siguiente código:

HashSet hs = new HashSet();
hs.add("hi"); -- (1)
hs.add("hi"); -- (2)

hs.size()dará 1 ya HashSetque no permite duplicados, por lo que solo se almacenará un elemento.

Quiero saber si agregamos el elemento duplicado, ¿entonces reemplaza el elemento anterior o simplemente no lo agrega?

Además, ¿qué pasará con HashMapel mismo caso?

Anand
fuente

Respuestas:

247

En el caso de HashMap, reemplaza el valor antiguo con el nuevo.

En el caso de HashSet, el elemento no se inserta.

Keppil
fuente
1
¿No estoy seguro de lo que me falta, pero el código fuente parece indicar lo contrario? ¿Veo que no verifican el respaldo HashMappara ver si keyya existe antes de llamar putal respaldo map?
mystarrocks
10
@mystarrocks: La clave es el elemento de la Set, y eso nunca es reemplazado por la put()operación.
Keppil
1
ah lo entiendo ahora. Comprendí que la clave es el elemento de la Set, pero me di cuenta de que put()solo anulará el valor, no la clave. En este caso, es el mismo valor puesto junto a la clave nuevamente, lo que puede o no ser mejor que verificar si la clave existe y poner. De cualquier manera, entiendo cómo funciona.
mystarrocks
Por curiosidad, ¿por qué HashMap y HashSet eligen ser así?
Helin Wang
@HelinWang: No creo que haya sido planeado, creo que es solo un efecto de HashSetser implementado en forma de a HashMap. Sin embargo, es difícil saberlo, a menos que sea uno de los desarrolladores de las clases.
Keppil
47

Lo primero que debe saber es que HashSetactúa como a Set, lo que significa que agrega su objeto directamente HashSety no puede contener duplicados. Simplemente agrega tu valor directamente HashSet.

Sin embargo, HashMapes un Maptipo. Eso significa que cada vez que agrega una entrada, agrega un par clave-valor.

En HashMappuede tener valores duplicados, pero no claves duplicadas. En HashMapla nueva entrada se reemplazará la anterior. La entrada más reciente estará en el HashMap.

Comprender el enlace entre HashMap y HashSet:

Recuerde, HashMapno puede tener claves duplicadas. Detrás de la escena HashSetusa a HashMap.

Cuando intentas agregar cualquier objeto a HashSet, esta entrada se almacena realmente como una clave en HashMapel mismo, HashMapque se usa detrás de escena HashSet. Dado que este subyacente HashMapnecesita un par clave-valor, se genera un valor ficticio para nosotros.

Ahora, cuando intente insertar otro objeto duplicado en el mismo HashSet, nuevamente intentará insertarlo como una clave en la HashMapmentira debajo. Sin embargo, HashMapno admite duplicados. Por lo tanto, HashSetseguirá teniendo como resultado un solo valor de ese tipo. Como nota al margen, para cada clave duplicada, dado que el valor generado para nuestra entrada en HashSet es un valor aleatorio / ficticio, la clave no se reemplaza en absoluto. se ignorará como eliminar la clave y volver a agregar la misma clave (el valor ficticio es el mismo) no tendría ningún sentido.

Resumen:

HashMappermite duplicar values, pero no keys. HashSetno puede contener duplicados.

Para jugar si la adición de un objeto se completó con éxito o no, puede verificar el booleanvalor devuelto cuando llama .add() y ver si regresa trueo false. Si regresó true, se insertó.

Palanqueta
fuente
HashMap allows duplicate valuesHashMap reemplaza el valor anterior por el nuevo.
Alex78191
20

Los documentos son bastante claros en esto: HashSet.add no reemplaza:

Agrega el elemento especificado a este conjunto si aún no está presente. Más formalmente, agrega el elemento e especificado a este conjunto si este conjunto no contiene ningún elemento e2 tal que (e == null? E2 == null: e.equals (e2)). Si este conjunto ya contiene el elemento, la llamada deja el conjunto sin cambios y devuelve falso.

Pero va a sustituir:HashMap.put

Si el mapa contenía previamente una asignación para la clave, se reemplaza el valor anterior.

pb2q
fuente
4

En el caso de HashSet, NO lo reemplaza.

De los documentos:

http://docs.oracle.com/javase/6/docs/api/java/util/HashSet.html#add(E )

"Agrega el elemento especificado a este conjunto si aún no está presente. Más formalmente, agrega el elemento especificado e a este conjunto si este conjunto no contiene ningún elemento e2 tal que (e == null? E2 == null: e.equals ( e2)). Si este conjunto ya contiene el elemento, la llamada deja el conjunto sin cambios y devuelve falso ".

Bob Provencher
fuente
1

Corrígeme si me equivoco, pero lo que entiendes es que con cadenas, "Hola" == "Hola" no siempre se hace realidad (porque no son necesariamente el mismo objeto).

Sin embargo, la razón por la que obtiene una respuesta de 1 es porque la JVM reutilizará los objetos de cadenas siempre que sea posible. En este caso, la JVM está reutilizando el objeto de cadena y, por lo tanto, sobrescribe el elemento en el Hashmap / Hashset.

Pero no tiene garantizado este comportamiento (porque podría ser un objeto de cadena diferente que tiene el mismo valor "Hola"). El comportamiento que ve es solo debido a la optimización de la JVM.

Nick Rippe
fuente
0

Primero debe verificar el método put en el mapa Hash, ya que HashSet está respaldado por HashMap

  1. Cuando agrega un valor duplicado, diga una Cadena "Uno" en HashSet,
  2. Se insertará una entrada ("uno", PRESENTE) en Hashmap (para todos los valores agregados en el conjunto, el valor será "PRESENTE", que si es de tipo Object)
  3. Hashmap agrega la entrada en el mapa y devuelve el valor, que en este caso es "PRESENTE" o nulo si la entrada no está allí.
  4. El método add de Hashset luego devuelve verdadero si el valor devuelto de Hashmap es nulo, de lo contrario es falso, lo que significa que ya existe una entrada ...
shiv
fuente
0

Para decirlo de otra manera: cuando inserta un par clave-valor en un HashMap donde la clave ya existe (en cierto sentido, hashvalue () da el mismo valor e igual () es cierto, pero los dos objetos aún pueden diferir de varias maneras ), la clave no se reemplaza pero se sobrescribe el valor. La clave solo se usa para obtener el valor hash () y encontrar el valor en la tabla con él. Dado que HashSet usa las claves de un HashMap y establece valores arbitrarios que realmente no importan (para el usuario) como resultado, los Elementos del conjunto tampoco se reemplazan.

Marco Rothley
fuente
0

HashMapbásicamente contiene lo Entryque posteriormente contiene Key(Object)y. Value(Object)Internamente HashSetsonHashMap y HashMapreemplazan los valores como algunos de ustedes ya señalaron ... pero ¿realmente reemplaza las claves? No ... y ese es el truco aquí. HashMapmantiene su valor como clave en el subyacente HashMapy el valor es solo un objeto ficticio. Por lo tanto, si intenta reinsertar el mismo valor en HashMap (clave en el mapa subyacente), simplemente reemplaza el valor ficticio y no la clave (valor para HashSet).

Mire el código a continuación para la clase HashSet:

public boolean  [More ...] add(E e) {

   return map.put(e, PRESENT)==null;
}

Aquí e es el valor para HashSet pero la clave para el mapa subyacente. Y la clave nunca se reemplaza. Espero poder aclarar la confusión.

Kunal Kumar
fuente