On the internal order of HashMap, Hashtable, TreeMap and Linkedhashmap

Source: Internet
Author: User
Tags concurrentmodificationexception

For HashMap, Hashtable, TreeMap, linkedhashmap of the internal sorting, found that a lot of people on the internet have misunderstood.

For example, some people think:

Hashtable.keyset () Descending

Treemap.keyset () Ascending

Hashmap.keyset () Disorderly order

Linkedhashmap.keyset () Original sequence

Some people think that the difference between keyset and EntrySet is caused by. So I'm going to go through two traversal ways to give you a test.

Put all the questions you need to demonstrate before you look at the code and see the results:

Internal sorting of 1.HashMap, Hashtable, TreeMap, Linkedhashmap

2. Is there a difference between using keyset and entryset to traverse the results?

3.HashMap, Hashtable, TreeMap, linkedhashmap initial default size


Research for some days, with some results, are tested through the code, pro-Test Effective ~ ~ ~ (respectively to the int,string test, the main look at the sort of key)

(The final statement, everyone first do not spit pattern problem, I just do a test, do not affect the actual operation, thank)


First of all, to reproduce the online opinion results, look at my Code

Package testcollections;
Import java.util.*;

Import Java.util.Map.Entry; public class Testoforderofmap {///test keyset sort public void testofkeyset (map map, Object obj[]) {for (int i=0; i<obj. Length
		i++) {map.put (Obj[i], obj[i]);  } if (map instanceof Linkedhashmap) {//linkedhashmap is also a hashmap, so test it in front System.out.println ("Linkedhashmap" + ":"
		+ map);
		}else if (map instanceof HashMap) {System.out.println ("HashMap" + ":" + map);
		}else if (map instanceof Hashtable) {System.out.println ("Hashtable" + ":" + map);
		}else if (map instanceof TreeMap) {System.out.println ("TreeMap" + ":" + map);
		} System.out.print ("key:");
    	 Iterator it = Map.keyset (). iterator (); <span style= "White-space:pre" > </span>while (It.hasnext ()) {<span style= "White-space:pre" >
                        ;/span>object key = It.next ();
       System.out.print (key+ ""); <span style= "White-space:pre" > </span>} <span style= "White-space:pre "> </span>system.out.println (); ///test EntrySet sort public void testofentryset (map map, Object obj[]) {for (int i=0; i<obj.length; i++) {map.put (
		Obj[i], obj[i]);  } if (map instanceof Linkedhashmap) {//linkedhashmap is also a hashmap, so test it to the front System.out.println ("Linkedhashmap" + ":" +
		MAP);
		}else if (map instanceof HashMap) {System.out.println ("HashMap" + ":" + map);
		}else if (map instanceof Hashtable) {System.out.println ("Hashtable" + ":" + map);
		}else if (map instanceof TreeMap) {System.out.println ("TreeMap" + ":" + map);
		} System.out.print ("key:");
        Iterator it = Map.entryset (). iterator (); <span style= "White-space:pre" > </span>while (It.hasnext ()) {<span style= "White-space:pre" > &L
           T;/span>entry e = (Entry) it.next ();
        <span style= "White-space:pre" > </span>system.out.print (E.getkey () + ""); <span style= "White-space:pre" > </span>} <span Style= "White-space:pre" > </span> System.out.println ();
		 
		 public static void Main (string[] args) {testoforderofmap test = new Testoforderofmap ();					HashMap hm1 = new HashMap ();	 
		 The first set is the key Hashtable ht1 = new Hashtable () that is used to test the int type.
		 TreeMap TM1 = new TreeMap ();		
		 
		 Linkedhashmap lhm1 = new Linkedhashmap ();
		 
		 Integer a[] = new Integer[]{3, 2, 5, 1, 4};
		 In the test keyset, key is the sort of number System.out.println ("Here is the keyset test:");
		 Test.testofkeyset (HM1, a);
		 Test.testofkeyset (ht1, a);
		 Test.testofkeyset (TM1, a);
		 
		Test.testofkeyset (LHM1, a);
		 In the test EntrySet, the key is a numeric sort System.out.println ();
		 System.out.println ("Here is the test of EntrySet:");
		 Test.testofentryset (HM1, a);
		 Test.testofentryset (ht1, a);
		 Test.testofentryset (TM1, a);
		 
	 Test.testofentryset (LHM1, a);
 }
}

Look at the results


Figure 1


Do you think it's the same as the above, Bo Lord, you tease us.

Hashtable.keyset () Descending

Treemap.keyset () Ascending

Hashmap.keyset () Disorderly order

Linkedhashmap.keyset () original sequence and listen to the blogger slowly explain Oh, here is sure that keyset and entryset traverse the result is exactly the same, prove the 2nd, then 1th,

If I put the above Integer a[] = new Integer[]{3, 2, 5, 1, 4}; Change to Integer a[] = new integer[]{13, 2, 5, 1, 4}; Which is to change the 3 to 13,

You'll see the results.


Figure 2


is not to say, Yi, this is what ghost. Is the result of the above argument is wrong Ah,

Hashtable.keyset () Descending//Error

Treemap.keyset () ascending//correct

Hashmap.keyset () disorderly//Can be said to be wrong, because you still do not understand its principle

Linkedhashmap.keyset () Yuan Xi//Can be said to be wrong, because you still do not understand its principle, this and Linkedhashmap construction method, later I will say to see a few sets of results, listen to my analysis. (I'll just list the results of keyset, because EntrySet is like keyset)

If I put the above Integer a[] = new Integer[]{3, 2, 5, 1, 4}; Change to Integer a[] = new integer[]{16, 2, 5, 1, 4};


Figure 3


If I put the above Integer a[] = new Integer[]{3, 2, 5, 1, 4}; Change to Integer a[] = new integer[]{11, 2, 5, 1, 4};


Figure 4

If I put the above Integer a[] = new Integer[]{3, 2, 5, 1, 4}; Change to Integer a[] = new integer[]{0, 65, 3, 17, 32};


Figure 5


You can see the clue is not, is this, if you have seen these collection of source code brother and sister may know that their traversal is related to their storage, and storage and the size of the container,

In cases where we create a container without specifying the container size, the container generally has a default size, which is well understood.

The default size of the HASHMAP is 16, each increase doubles, the default size of Hashtable is 11, twice times the original increment 1,treemap and Linkedhashmap are temporarily uncertain or infinitely large,

But it doesn't affect our understanding here. Well, HashMap will be based on key hashcode again hash calculation, and finally hashed into the entry, look at the source

 public V-put (K key, V value) {if (key = null) return Putfornullkey (value); int hash = hash (key); <span style= "White-space:pre" > </span>//hash value int i = indexfor (hash, tab Le.length);
            Locate the position to insert for (entry<k,v> e = table[i]; e!= null; e = e.next) {Object K;
                if (E.hash = = Hash && ((k = e.key) = = Key | | key.equals (k))) {V oldValue = E.value;
                E.value = value;
                E.recordaccess (this);
            return oldValue;
        }} modcount++;
    AddEntry (hash, key, value, I);//Add it to the list corresponding to the hash value return null; }
Final int hash (Object k) {
        int h = 0;
        if (usealthashing) {
            if (k instanceof String) {return
                Sun.misc.Hashing.stringHash32 ((String) k);
            }
            h = hashseed;
        }

        H ^= K.hashcode ();

        This function ensures so hashcodes that differ only by
        //constant multiples in each bit position have a bounded< c10/>//number of collisions (approximately 8 at default load factor).
        H ^= (H >>>) ^ (h >>>); <span style= "White-space:pre" >	</span>//This is a complex, recalculated hash value C13/>return h ^ (H >>> 7) ^ (H >>> 4);
    }
static int indexfor (int h, int length) {return
        H & (length-1);      is actually the modulus
    }
void AddEntry (int hash, K key, V value, int bucketindex) {
        if (size >= threshold) && (null!= table[bucket Index]) {
            Resize (2 * table.length);    Expansion
            hash = (null!= key)? Hash (key): 0;
            Bucketindex = Indexfor (hash, table.length);//Inserts "Key-value" into the specified location, Bucketindex is the location index.
        }

        Createentry (hash, key, value, Bucketindex);
    
void Createentry (int hash, K key, V value, int bucketindex) {
        entry<k,v> e = Table[bucketindex];
        Table[bucketindex] = new entry<> (hash, key, value, e);//Create Entry. Inserts "Key-value" into the specified location. 
        size++;
    }
Take the value of the process is the same, is based on the location of key storage to take, so said HashMap is not disorderly, but according to the hash value to access, but this hash value, we are more difficult to calculate it.
There is a small discovery that when the value of the key does not exceed 16 o'clock, hashmap access is accessed in the order of small to large.

Figure 6


As for Hashtable access, similar to HashMap, but in the method before adding a synchronized synchronization field, followed by the calculation of the hash value a little different
There is a small discovery that when the number of keys does not exceed 11 and the value of the key does not exceed 11 o'clock, hashtable access is accessed in order from large to small.


Figure 7

T

Reemap is better understood, the bottom of the implementation of the use of red and black trees, key in accordance with the order of small to large, buttoned up.

Linkedhashmap here, there are two orders, one is the order of insertion, one is the order of access, depending on whether the parameters in the constructor Accessorder is true, and when Accessorder is true, Traversal linkedhashmap is stored in the order of access, and when Accessorder is false, Linkedhashmap is stored in the order of insertion, and defaults to false. See examples.

Package testcollections;

Import java.util.*;
Import Java.util.Map.Entry;

public class Testoforderofmap {public

	void Testofkeyset (map map, Object obj[]) {for
		(int i=0; i<obj.length; i+ +) {
			map.put (obj[i], obj[i]);
		}
		
		System.out.println ("Linkedhashmap" + ":" + map);
		System.out.print ("key:");
		Iterator it =  map.keyset (). iterator ();
    		while (It.hasnext ()) {
        		Object key = It.next ();
           	 System.out.print (key+ "");
       		}		
        	System.out.println ();
	}
	
	 public static void Main (string[] args) {
		 testoforderofmap test = new Testoforderofmap ();
		 Linkedhashmap lhm1 = new Linkedhashmap ();		
		 Integer a[] = new Integer[]{7, 0, 5, ten, 6, 2, 8, 3, to};
		
		 Test.testofkeyset (LHM1, a);
	 }
}
Results:

Figure 8


The order of insertion is Integer a[] = new Integer[]{7, 0, 5, 10, 17, 6, 2, 8, 3, 31}
The order of printing is also 7, 0, 5, 10, 17, 6, 2, 8, 3, 31
Look at the order of access, put the above
Linkedhashmap lhm1 = new Linkedhashmap ();	

Change to Linkedhashmap lhm1 = new Linkedhashmap (0.75f,true), all modified as follows:

Package testcollections;
Import java.util.*;


Import Java.util.Map.Entry; public class Testoforderofmap {<span style= "white-space:pre" > </span>public void Testofkeyset (map map, Obje CT obj[]) {<span style= "White-space:pre" > </span>for (int i=0; i<obj.length; i++) {<span style= "white-
 Space:pre "> </span>map.put (Obj[i], obj[i]); <span style= "White-space:pre" > </span>} <span style= "White-space:pre" > </span>
 
 System.out.println ("Linkedhashmap" + ":" + map); <span style= "White-space:pre" > </span>system.out.print ("Access      " + map.get (7) + "After:  "
 );
 <span style= "White-space:pre" > </span>system.out.println (map);
 <span style= "White-space:pre" > </span>system.out.print ("Access      " + map.get (10) + "after:");
 
 <span style= "White-space:pre" > </span>system.out.println (map); <span style= "White-space:pre" > </span>system.out.prinT ("last Key:");
<span style= "White-space:pre" > </span>iterator it =  map.keyset (). iterator ();     <span style= "White-space:pre" > </span>while (It.hasnext ()) {      <span sty
le= "White-space:pre" > </span>object key = It.next ();
            <span style= "White-space:pre" > </span>system.out.print (key+ "");         <span style= "White-space:pre" > </span>}         <span sty
 le= "White-space:pre" > </span>system.out.println (); <span style= "White-space:pre" > </span> <span style= "White-space:pre" > </span>public static void Main (string[] args) {<span style= "white-space:pre" > </span>testoforderofmap test = new TESTOFORDEROFMA
 P (); 
 <span style= "White-space:pre" > </span>linkedhashmap lhm1 = new Linkedhashmap (0.75f,true); <span style= "White-space:pre" > </spaN>integer a[] = new Integer[]{7, 0, 5, 10, 17, 6, 2, 8, 3, 31};
 <span style= "White-space:pre" > </span>test.testofkeyset (LHM1, a); <span style= "White-space:pre" > </span>}
Result is


Figure 9


Analysis: Insert the order of 7, 0, 5, ten, 6, 2, 8, 3, Map.get (7) After, that is, after accessing 7, put 7 at the end of the list, that is, after 31, into a

0,5,10,17,6,2,8,3,31,7 then after Map.get (10), that is, after visiting 10, put 10 on the end of the list, that is 7, after the 0,5,17,6,2,8,3,31,7,10

This is stored in order of access, and it is said that the benefit is that you can implement LRU, that is, to put all the objects that have been accessed at the end, then the objects that have not been accessed are at the front, and when memory is not available,

You can implement permutations by simply deleting objects that were not previously used for the last time to accept new objects.

A little knowledge is attached below,
When the constructor parameter Accessorder is true, the Linkedhashmap get () method changes the data list, and what happens. Look at the results first.


Figure 10


Ah oh, the error, java.util.ConcurrentModificationException, first of all, when using EntrySet to traverse the time will not be wrong, with the keyset traversal time will be wrong, is the following section of code

<span style= "White-space:pre" >		</span>iterator it =  map.keyset (). iterator ();
		while (It.hasnext ()) {
    		<span style= "White-space:pre" >	</span>object key = It.next ();
       	 	 <span style= "White-space:pre" >	</span>system.out.print (key+ "");
       	 	 <span style= "White-space:pre" >	</span>system.out.print (Map.get (key));
   			
This is why ah, according to the source code of the error is very good understanding

  <span style= ' white-space:pre ' >	</span>nextentry () {
            if (modcount!= expectedmodcount)//Entry The number of times modified is not equal to the number of times it is expected to be modified, so it throws the concurrentmodificationexception exception
                throw new Concurrentmodificationexception ();
            if (NextEntry = header)
                throw new Nosuchelementexception ();

            Entry<k,v> e = lastreturned = NextEntry;
            NextEntry = E.after;
            return e;
        }
Because when Accessorder is true, the Linkedhashmap get () method changes the data list, because each time the key corresponds to the entry is placed at the end of the list (which has been analyzed), and keyset The iterator object does not allow us to dynamically change the Linkedhashmap data list structure, as the source code above says, the number of times the Entry is modified does not equal the number of times it is expected to be modified. Because it's a good order, and you're now going to visit each one, put it at the very end, then I went to find it next time but found that the original is not, because this is the dynamic, who can not detect, only when the access to it is not found in that position (take the example above, It's not a problem to visit the first position at 7. After the visit, put 7 to the last side, the original second position corresponding to 0, is now top to the first position, then I will visit the next round of 0 when the 0 disappeared, replaced by 5, then it should be an error? Now you see. It's like I use my schoolbag to carry 10 ping-pong balls to the gym, and suddenly a classmate sneaks away a also put a bad put my schoolbag inside, also don't say hello to me, I did not see, after one hours, I put 9 of them are broken, want to take the tenth to use, found, Yi, how is bad Ah, Who changed my table tennis ah, I should call the police ah (haha, a joke)
That why Accessorder is false, the use of keyset traversal will not appear this anomaly ah, because false, is stored in the order of insertion, did not destroy the original order Ah, it will not appear

Modcount!= Expectdmodcount the situation.

Then why EntrySet go through the time can not be wrong ah. Because, keyset just put all the keys in the set in advance, not the value corresponding to the

And EntrySet is the advance of all the entry are placed in the set, entry has a key corresponding to the value, so key changes in value will also follow the change, will not find dislocation of the situation.

Two source comparison

Private class Keyiterator extends linkedhashiterator<k> {public
        K next () {return nextentry (). Getkey ()}
    
  Private class Entryiterator extends linkedhashiterator<map.entry<k,v>> {public
        map.entry<k,v> Next () {return nextentry ();}
    }

The return inside the next () has one more getkey () in the Keyiterator class.

Remember, you're going to make this mistake in three conditions. 1,accessorder set to True. 2, with keyset traversal. 3, using the Map.get (key) method

At this point, the first three questions have been solved.


So back, we're going to test what happens when key is a string object, but it's very similar.

Package testcollections;
Import java.util.*;

Import Java.util.Map.Entry;
			public class Testoforderofmap {public void Testofkeyset (map map, Object obj[]) {for (int i=0; i<obj.length; i++) {
		Map.put (Obj[i], obj[i]);  } if (map instanceof Linkedhashmap) {//linkedhashmap is also a hashmap, so test it in front System.out.println ("Linkedhashmap" + ":"
		+ map);
		}else if (map instanceof HashMap) {System.out.println ("HashMap" + ":" + map);
		}else if (map instanceof Hashtable) {System.out.println ("Hashtable" + ":" + map);
		}else if (map instanceof TreeMap) {System.out.println ("TreeMap" + ":" + map);
		} System.out.print ("key:");
    	 Iterator it = Map.keyset (). iterator (); <span style= "White-space:pre" > </span>while (It.hasnext ()) {<span style= "White-space:pre" > &L
           	 T;/span>object key = It.next ();
       	 <span style= "White-space:pre" > </span>system.out.print (key+ "");		<span style= "White-space:pre" > </span>}
       <span style= "White-space:pre" > </span>system.out.println ();
		 
		 public static void Main (string[] args) {testoforderofmap test = new Testoforderofmap ();					HashMap hm2= new HashMap ();	 
		 The second set of sets is used to test string type key Hashtable ht2 = new Hashtable ();
		 TreeMap tm2 = new TreeMap ();		
		 
		Linkedhashmap lhm2 = new Linkedhashmap (0.75f, true);
		 Integer a[] = new Integer[]{7, 0, 5, 10, 17,6,2,8,3,31};
		 
		 String a[] = new string[]{"AA", "OK", "You", "abc", "67k"};
		 In the test keyset, key is the sort of number System.out.println ("Here is the keyset test:");
		 Test.testofkeyset (HM2, a);
		 Test.testofkeyset (Ht2, a);
		 Test.testofkeyset (TM2, a);
		 
		Test.testofkeyset (LHM2, a);
		 /*//Test EntrySet Key is a number of sorting System.out.println ();
		 System.out.println ("Here is the test of EntrySet:");
		 Test.testofentryset (HM2, a);
		 Test.testofentryset (Ht2, a);
		 Test.testofentryset (TM2, a); Test.testofentryset (LHM2, a); */}
Results


Figure 11


Analysis, HashMap and Hashtable are no chapters to follow, according to its own hashcode to store, TreeMap, according to the first letter of the key to sort, first number to uppercase and lowercase letters.

Linkedhashmap is still the same as the above analysis. Complete.



Summarize:

1, HASHMAP, Hashtable storage sequence and key corresponding to the hashcode, but there are small rules, when the value of key does not exceed 16 o'clock, HASHMAP access is in accordance with the order of small to large access, when the number of keys does not exceed 11 and the value of the key is not more than 1 1 o'clock, hashtable access is accessed in order from large to small. The order of TreeMap is from small to large, linkedhashmap in order of two, one is in the order of insertion, one is in order of access, depending on whether the accessorder is true.

2, keyset and EntrySet traversal results are not different, there is a little difference is in the linkedhashmap when stored in the order of access, using the keyset traversal get () method will error.

3, the default size of the HASHMAP is 16, each growth will double, hashtable default size of 11, each growth of the original twice times plus 1,treemap and linkedhashmap can not be sure or say infinitely large, but here does not affect our understanding.


Days are fast, the first time in life to write such a long blog, there are any flaws in the place also hope that you do not hesitate to enlighten, after all, a person's thinking depth is limited, 3Q oh. (and have to say csdn write a blog edit box layout is very problematic)


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.