简体   繁体   中英

Why does toString function of a HashMap prints itself with a different order?

I have this very simple piece of code, and I was just trying to play a bit with different kind of objects inside a Map.

//There's a bit of spanish, sorry about that
//just think 'persona1' as an object with
//a string and an int
Map mapa = new HashMap();
mapa.put('c', 12850);
mapa.put(38.6, 386540);
mapa.put("Andrés", 238761);
mapa.put(14, "Valor de 14");
mapa.put("p1", persona1);
mapa.put("Andrea", 34500);

System.out.println(mapa.toString());

And then I expect from console something like:

{c=12850, 38.6=386540, Andrés=238761, 14=Valor de 14, p1={nombre: Andres Perea, edad: 10}, Andrea=34500}

But susprisingly for me I got same data in different order:

{38.6=386540, Andrés=238761, c=12850, p1={nombre: Andres Perea, edad: 10}, Andrea=34500, 14=Valor de 14}

It doesn't matter if I try other kind of objects, even just Strings or numeric types, it always does the same, it makes a different without-apparently-any-sense order.

Can someone give me a hint why this happens? Or may be something too obvious I'm missing?

I'm using Java 1.7 and Eclipse Juno.

As per Oracle's documentation

The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls. This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.

Refer to HashMap JavaDocs.

There are 3 class which implements map interface in java. 1. hashMap: Id does not guarantee any order. 2. Linked HashMap:It will store them in insertion order. 3. TreeMap: It will store in ascending order.(ASCII value)

So As per your requirement you can use Linked HashMap instead of HashMap.so instead of writing

Map mapa = new HashMap();

create object of Linked HashMap

Map mapa = new LinkedHashMap();

follow below link for more info.

http://docs.oracle.com/javase/tutorial/collections/interfaces/map.html

HashMap not guaranteed the order of element. If you want to keep order use LinkedHashMap .

See following case

    Map<Integer,String> unOrderedMap=new HashMap<>();
    unOrderedMap.put(1,"a");
    unOrderedMap.put(3,"a");
    unOrderedMap.put(2,"a");
    System.out.println("HashMap output: "+unOrderedMap.toString());

    Map<Integer,String> orderedMap=new LinkedHashMap<>();
    orderedMap.put(1,"a");
    orderedMap.put(3,"a");
    orderedMap.put(2,"a");
    System.out.println("LinkedHashMap output: "+orderedMap.toString());

Output:

   HashMap output: {1=a, 2=a, 3=a}
   LinkedHashMap output: {1=a, 3=a, 2=a}

Maps does not maintain the order the order in which elements were added, List will maintain the order of elements

"The order of a map is defined as the order in which the iterators on the map's collection views return their elements. Some map implementations, like the TreeMap class, make specific guarantees as to their order; others, like the HashMap class, do not."

This is how a hashmap works: (citing from another source)


It has a number of "buckets" which it uses to store key-value pairs in. Each bucket has a unique number - that's what identifies the bucket. When you put a key-value pair into the map, the hashmap will look at the hash code of the key, and store the pair in the bucket of which the identifier is the hash code of the key. For example: The hash code of the key is 235 -> the pair is stored in bucket number 235. (Note that one bucket can store more then one key-value pair).

When you lookup a value in the hashmap, by giving it a key, it will first look at the hash code of the key that you gave. The hashmap will then look into the corresponding bucket, and then it will compare the key that you gave with the keys of all pairs in the bucket, by comparing them with equals().

Now you can see how this is very efficient for looking up key-value pairs in a map: by the hash code of the key the hashmap immediately knows in which bucket to look, so that it only has to test against what's in that bucket.

Looking at the above mechanism, you can also see what requirements are necessary on the hashCode() and equals() methods of keys:

  • If two keys are the same (equals() returns true when you compare them), their hashCode() method must return the same number. If keys violate this, then keys that are equal might be stored in different buckets, and the hashmap would not be able to find key-value pairs (because it's going to look in the same bucket).

  • If two keys are different, then it doesn't matter if their hash codes are the same or not. They will be stored in the same bucket if their hash codes are the same, and in this case, the hashmap will use equals() to tell them apart.


Now, when you put all your "key-value" pairs in the hashmap, and print them, it prints them in some random order of the keys which got generated by hashing the value you supplied for keys.

If your requirement is still to maintain the ordering, you can use the LinkedHashMap in Java.

Hope this helps :-)

Edit: Original Post: How does a Java HashMap handle different objects with the same hash code?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM