0

Consider the following code snippet :

public class MainClass {

public static void main(String[] arg)       {
    Map<String, Object> map = new HashMap<>();

    map.put("ONE", new BigInteger("1"));
    map.put("TWO", new BigInteger("2"));
    map.put("THREE", new BigInteger("3"));
    map.put("FOUR", new BigInteger("4"));
    map.put("FIVE", new BigInteger("5"));
    map.put("SIX", new BigInteger("6"));

    System.out.println("Hello !");
}

The result is:

  • Map's size is 6.
  • Map's table contains the following content:

    [FIVE=5,
     SIX=6,
     ONE=1,
     TWO=2,
     THREE=3]
    

FOUR disappeared. As a comment stated before, it would be wise to calculate the hashCode of my entries, modulo the size of the map. It gives the following result:

ONE : 0
TWO : 0
THREE : 1
FOUR : 2
FIVE : 3
SIX : 4

As we can see, the hashCode does not indicate anything considering the collision of FOUR with any value. This also works with ConcurrentHashMap and LinkedHashMap, so I guess it is a HashMap problem.

Can someone explain to me what is actually going on ? I'm quite lost on this one.


I'm working with:

  • Eclipse Neon
  • JDK 8
Gurwinder Singh
  • 38,557
  • 6
  • 51
  • 76
Yassine Badache
  • 1,810
  • 1
  • 19
  • 38
  • 6
    I have executed your code and the result for me is: `{ONE=1, TWO=2, THREE=3, FOUR=4, SIX=6, FIVE=5}` – canillas Feb 12 '18 at 08:22
  • Is this the whole code? – Maroun Feb 12 '18 at 08:23
  • 3
    Makes no sense as collisions don't prevent element adding. An element is replaced only as the key of the added element is equals to its key. Note that your code doesn't output the map. – davidxxx Feb 12 '18 at 08:24
  • Yes it is, and I would love to have your result @canillas, I swear. It would have saved me some effort. – Yassine Badache Feb 12 '18 at 08:32
  • I mean that maybe the error is not in this piece of code... It's the whole code? – canillas Feb 12 '18 at 08:36
  • 1
    @canillas this code is sufficient and completely fine. Read the answers for the reason behind this behavior. Yassine, you might want to look at [this question](https://stackoverflow.com/questions/6493605/how-does-a-java-hashmap-handle-different-objects-with-the-same-hash-code?noredirect=1) for more details about HashMap's internals. – Malte Hartwig Feb 12 '18 at 08:37
  • Your code is fine. Eran and Seelenvirtuose's answer showed me why I was wrong. `HashMap` are working with buckets, and `FOUR` is stored in the same bucket as `ONE`. The difference between actual size and table put me in trouble there, thank you all for your answers. – Yassine Badache Feb 12 '18 at 08:40

2 Answers2

4

"FOUR" did not disappear. You saw for yourself that the map's size is 6, and if you'll print the map, you'll see all 6 entries.

If you look more carefully in your debugger, you'll see that keys "ONE" and "FOUR" are mapped to the same bucket (index 7). This can happen even if they don't have the same hash code (since HashMap performs some additional computation on the hashCode() of the key, and then performs % table.length on the result to obtain the index of the bucket).

enter image description here

In your example, the hash value computed for "ONE" is 78407, and for "FOUR" it's 2163975. Since the default initial number of buckets is 16, the bucket is computed by 78407 % 16 == 2163975 % 16 == 7, so both keys are stored in the same bucket.

Eran
  • 387,369
  • 54
  • 702
  • 768
4

The HashMap's internal table (which is in fact a simple array) does not store the values but a list-like structure whose elements now store several values.

A hash map calculates the hash value of the keys being put into it. Distinct keys that yet have the same hash code go into the same list (indexed in the table array).

Have a look into the source code of HashMap.Node:

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;
    ...
}

Each node inside that list stores the key, the value, the hash code, and a pointer to the next node of that list.

Your example code builds up the following table:

 [2] FIVE = 5    =>   null
 [3] SIX = 6     =>   null
 [7] ONE = 1     =>   FOUR = 4   =>   null
[13] TWO = 2     =>   null
[15] THREE = 3   =>   null

By the way ... Printing the whole map yields the following:

{FIVE=5, SIX=6, ONE=1, FOUR=4, TWO=2, THREE=3}
Seelenvirtuose
  • 20,273
  • 6
  • 37
  • 66