una repetidos numeros matriz eliminar elementos contar caracteres cadena arreglo array java hashmap hashset

matriz - numeros repetidos en un arreglo java



¿Cómo HashSet no permite duplicados? (6)

Como puede ver, el método HashSet.add agrega el elemento a HashMap.put como una clave, no como un valor. El valor se reemplaza en HashMap no en la clave.

Estaba revisando el método add de HashSet . Se menciona que

Si este conjunto ya contiene el elemento, la llamada deja el conjunto sin cambios y devuelve falso.

Pero el método add guarda internamente los valores en HashMap

public boolean add(E e) { return map.put(e, PRESENT)==null; }

El método put de HashMap establece que

Asocia el valor especificado con la clave especificada en este mapa. Si el mapa contenía previamente una asignación para la clave, se reemplaza el valor anterior.

Entonces, si el método put de HashMap reemplaza el valor anterior, ¿cómo el método HashSet add deja el conjunto sin cambios en caso de elementos duplicados?


Desde javadocs para HashMap.put (), "Asocia el valor especificado con la clave especificada en este mapa. Si anteriormente el mapa contenía una asignación para la clave, se reemplaza el valor anterior".

Por lo tanto, el valor del mapa será reemplazado, (que es un campo estático constante en la clase HashSet, y así se reemplaza la misma instancia), y la clave del mapa se mantiene intacta (que, de hecho, es el elemento de la colección Set)


La respuesta que puede estar buscando se reduce al hecho de que el hashmap de respaldo mapea los elementos del conjunto al valor PRESENT que se define en HashSet.java siguiente manera:

private static final Object PRESENT = new Object();

En el código fuente para HashMap.put tenemos:

386 public V put(K key, V value) { 387 if (key == null) 388 return putForNullKey(value); 389 int hash = hash(key.hashCode()); 390 int i = indexFor(hash, table.length); 391 for (Entry<K,V> e = table[i]; e != null; e = e.next) { 392 Object k; 393 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 394 V oldValue = e.value; 395 e.value = value; 396 e.recordAccess(this); 397 return oldValue; 398 } 399 } 400 401 modCount++; 402 addEntry(hash, key, value, i); 403 return null; 404 }

Debido a que la clave en cuestión ya existe, tomaremos el retorno anticipado en la línea 397. Pero podría pensar que se está realizando un cambio en el mapa en la línea 395, en la que parece que estamos cambiando el valor de una entrada en el mapa. Sin embargo, el valor del value está PRESENT . Pero como PRESET es estático y final, solo hay una instancia; ¡entonces la asignación e.value = value realidad no cambia el mapa, y por lo tanto el conjunto, en absoluto!


Ver HashMap#put :

Asocia el valor especificado con la clave especificada en este mapa. Si el mapa contenía previamente una asignación para la clave, se reemplaza el valor anterior.

Reemplaza la clave con el nuevo valor, de esta manera, no habrá duplicados en el HashSet .


PRESENT es solo un valor ficticio: al conjunto realmente no le importa qué es. Lo que importa al conjunto son las teclas del mapa. Entonces la lógica es así:

Set.add(a): map.put(a, PRESENT) // so far, this is just what you said the key "a" is in the map, so... keep the "a" key, but map its value to the PRESENT we just passed in also, return the old value (which we''ll call OLD) look at the return value: it''s OLD, != null. So return false.

Ahora, el hecho de que OLD == PRESENT no importa, y tenga en cuenta que Map.put no cambia la clave, solo el valor asignado a esa clave. Como las claves del mapa son lo que realmente le importa al Set , el Set se modifica.

De hecho, ha habido algún cambio en las estructuras subyacentes del Set : reemplazó un mapeo de (a, OLD) con (a, PRESENT) . Pero eso no es observable desde fuera de la implementación del Set . (Y sucede que ese cambio ni siquiera es un cambio real, ya que OLD == PRESENT ).


public boolean add(E e) { return map.put(e, PRESENT)==null; }

e es la clave, entonces, si e ya está presente, put no devolverá null . Por lo tanto, add devolverá falso.

JavaDoc para put :

el valor anterior asociado con la clave, o nulo si no había una asignación para la clave. (Un retorno nulo también puede indicar que el mapa asociaba previamente nulo con la clave).