0. Foreword
The difference between HashMap and Hashtable a relatively simple answer is:
(1) HashMap is not thread-safe, Hashtable is thread-safe.
(2) HashMap's keys and values allow NULL to exist, while Hashtable is not.
(3) HashMap efficiency is higher than hashtable because of the problem of thread safety and hash efficiency.
But if you keep asking: What is another thread-safe class in Java that is very similar to the HashMap feature?
Also thread-safe, it differs from Hashtable on-line synchronization. Take these questions and start today's article.
This article for the original, related content will continue to maintain, reproduced please indicate the source: http://blog.csdn.net/seu_calvin/article/details/52653711.
1. HashMap Overview
Java data storage mode has two kinds of structure, one is an array, the other is linked list, the former is characterized by continuous space, addressing quickly, but in addition to adding and deleting elements will have a larger movement, so the characteristics of the array is faster query speed, and more slowly.
And the linked list because the space is not continuous, addressing difficult, adding and deleting elements only need to modify the pointer, so the characteristics of the linked list is slow query speed, additions and deletions fast.
So is there a data structure to synthesize arrays and lists in order to play their respective advantages. The answer is a hash table. The storage structure of the hash table is shown in the following illustration:
From the above figure, we can see that the hash table is made up of array + linked list, in an array of length 16, each element stores the head node of a linked list, and the position of the array to be stored is obtained by using functions similar to the hash (Key.hashcode ())%len.
HashMap hash algorithm is the actual operation is through the bit operation, more efficient than modulo operation, the same can achieve the purpose of uniform distribution, and will be introduced later.
The data structure in which the key value pair is stored is actually a entity inner class defined in HashMap, and the array is implemented with the key, value, and next entity pointing to the next one.
2. Initialization of HashMap
There are two common ways to construct HashMap:
The first is a construction method that does not require parameters:
static final int default_initial_capacity = 16; The initial array length is
static final int maximum_capacity = 1 << 30;//maximum capacity 2 of 30 times/
/load factor is used to measure the degree of HashMap full
The method for calculating the real time load factor for HASHMAP is: size/capacity
static final float default_load_factor = 0.75f;//load Factor public
HashMap () {
this.loadfactor = default_load_factor;
threshold = (int) (default_initial_capacity * default_load_factor);
The default array length is
table = new Entry[default_initial_capacity];
Init ();
}
The second is to construct a parameter:
Public HashMap (int initialcapacity, float loadfactor) {
if (initialcapacity < 0)
throw new IllegalArgumentException ("Illegal initial capacity:" + initialcapacity);
if (initialcapacity > maximum_capacity)
initialcapacity = maximum_capacity;
if (loadfactor <= 0 | | Float.isnan (loadfactor))
throw new IllegalArgumentException ("Illegal load factor:" + loadfactor);
Find a power of 2 >= initialcapacity
int capacity = 1;
while (capacity < initialcapacity)
capacity <<= 1;
This.loadfactor = Loadfactor;
threshold = (int) (capacity * loadfactor);
Table = new Entry[capacity];
Init ();
}
From the source can see that the initialization of the array length of capacity,capacity value is always 2 n times, the size of the first parameter slightly larger or equal.
3. HashMap's put operation
Public V-Put (K key, V value) {
if (key = null) return
Putfornullkey (value);
int hash = hash (Key.hashcode ());
int i = indexfor (hash, table.length);
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);
return null;
}
3.1
the put key is null
As can be seen from the source code, HASHMAP is allowed to null key, will invoke the Putfornullkey () method:
Private v Putfornullkey (v value) {for
(entry<k,v> e = table[0]; e!= null; e = e.next) {
if (E.key = null) {
V oldValue = e.value;
E.value = value;
E.recordaccess (this);
Return OldValue
}
}
modcount++;
AddEntry (0, NULL, value, 0);
return null;
}
void AddEntry (int hash, K key, V value, int bucketindex) {
entry<k,v> e = Table[bucketindex];
Table[bucketindex] = new entry<k,v> (hash, key, value, e);
if (size++ >= threshold)
Resize (2 * table.length);
The Putfornullkey method iterates through the linked list with table[0] as the head of the chain, and if a key is null, replace its value and return the old value. Otherwise, the AddEntry method is invoked, and it is simple to place [Null,value] in the table[0] position and encapsulate the newly added key-value pair into a entity object, and next point to the Table[0 instance at the original entity.
The size represents the number of all key-value pairs that are stored in the HashMap.
Threshold = Capacity*loadfactor, the last few lines of code indicate that when the size of HashMap is greater than threshold, the resize operation is performed and the HashMap is expanded to twice times the original. Expansion needs to recalculate the position of each element in the array, as evidenced by the Table.length parameter in the Indexfor () method.
But expansion is a very performance-consuming operation, so if we have already foreseen the number of elements in HashMap, the number of preset elements can effectively improve the performance of HashMap. For example, we have 1000 elements, so we're going to declare new HASHMAP (2048), because we need to consider the default 0.75 expansion factor and the number of n times the group must be 2. If you use the declaration new HashMap (1024), you will be able to enlarge it in the put process.
3.2 the put key is not null
Copy the relevant code from the put method above for easy viewing:
int hash = hash (Key.hashcode ());
int i = indexfor (hash, table.length);
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);
return null;
}
As you can see from the source, the 1th and 2 lines compute the position of the array of key-value pairs that will be put into. Line 4th to determine whether the added key and with Table[i] as the linked list of linked lists all of the key-value pairs have duplicates, if repeat, replace value and return the old value, if there is no repetition of the call AddEntry method, above the logic of this method has been introduced.
The put operation for this hashmap has been introduced.
4. HashMap get Operation
Public V get (Object key) {
if (key = null) return
getfornullkey ();
int hash = hash (Key.hashcode ());
for (entry<k,v> e = table[indexfor (hash, table.length)]; e!= null; e = e.next) {
Object K;
if (E.hash = = Hash && ((k = e.key) = = Key | | key.equals (k)) return
E.value
;
return null;
}
Private V Getfornullkey () {for
(entry<k,v> e = table[0]; e!= null; e = e.next) {
if (E.key = null)
return e.value;
}
return null;
}
If you understand the previous put operation, then the get operation logic here is very easy to understand, the logic in the source code is very very clear.
Note that only if the corresponding value is not found, the return is null. or value itself is null. This can be done by ContainsKey () to make specific judgments.
Understand the above HashMap put and get operation principles, you can use the following small example to consolidate knowledge, the title is printed in the array of N/2 above the elements, we can be used hashmap characteristics to solve.
public class Hashmaptest {public
static void Main (string[] args) {
int [] A = {2,1,3,2,0,4,2,1,2,3,1,5,6,2,2,3};< C2/>map<integer, integer> Map = new hashmap<integer,integer> ();
for (int i=0; i<a.length; i++) {
if (Map.containskey (a[i))) {
int tmp = Map.get (A[i]);
Tmp+=1;
Map.put (A[i], TMP);
else{
map.put (A[i], 1);
}
set<integer> set = Map.keyset ();
for (Integer s:set) {
if (Map.get (s) >=a.length/2) {
System.out.println (s);
}
}}
}
5. Comparison of HashMap and Hashtable
Hashtable and HashMap adopt the same storage mechanism, the two implementations are basically consistent and different:
(1) HashMap is not thread-safe, Hashtable is thread-safe, and internal methods are synchronized modified.
(2) Because of synchronization, hash performance and other reasons, performance is certainly hashmap better, so Hashtable has been eliminated.
(3) HashMap allows the existence of null values, while the key values put in Hashtable can be thrown directly nullpointerexception as long as there is a null.
(4) The size of the HASHMAP default initialization array is 16,hashtable to 11. The former is multiplied by 2, and the hash is obtained using bit operation, and the efficiency is higher than modulo. The latter is multiplied by 2 plus 1, both prime and odd, so that the modulo hash result is more uniform.
Here originally I did not look at the specific hashing algorithm process, intend to roughly compare the difference on the past, but the recent sister to interview the United States Group Mobile development was asked a little more specific algorithm process, I was drunk ... However, congratulations on the success of the interview, starting salary of 20W, really envy, I hope that after a year to find a job can also shun smoothly.
To go to the bottom, look at the next two sets of hash algorithm. Look at the source is not difficult to understand.
HashMap hash function, where the key
static final int hash (Object key) {
int h, where the parameter is a key value pair is passed in;
return (key = = null)? 0: (H = key.hashcode ()) ^ (h >>>);
}
Returns the index of the hash value, the H & (length-1) operation is equivalent to the hash% length operation, but the & operation performance is better than the
static int indexfor (int h, int length) {
//len Gth must is a Non-zero power of 2 return
H & (length-1);
}
The hash function of Hashtable implements the
int hash = Key.hashcode ()
directly in the Put method. int index = (hash & 0x7fffffff)% Tab.length;
6. Comparison of Hashtable and Concurrenthashmap
First of all, the introduction of Concurrenthashmap, it is thread-safe implementation of the HashMap.
Hashtable in the use of the Synchronized keyword, which is actually a lock on the object, locked is the object as a whole, when the size of the hashtable increased to a certain time, performance will be drastically reduced, because the iteration needs to be locked for a long time.
Concurrenthashmap is the optimization of the above problem, its constructor is as follows, the default is 16,0.75,16.
public concurrenthashmap (int paramInt1, float paramfloat, int paramInt2) {//... int i = 0;
int j = 1;
while (J < ParamInt2) {++i;
J <<= 1;
} This.segmentshift = (32-i);
This.segmentmask = (j-1);
This.segments = Segment.newarray (j);
. int k = paramint1/j;
if (k * J < ParamInt1) ++k;
int L = 1;
while (L < k) L <<= 1;
for (int i1 = 0; I1 < this.segments.length ++i1) this.segments[i1] = new Segment (l, paramfloat);
Public V-Put (K Paramk, v paramv) {if (PARAMV = null) throw new NullPointerException (); int i = hash (Paramk.hashcode ()); The hash function here is not the same as in HashMap return this.segments[(i >>> this.segmentshift & this.segmentmask)].put (PARAMK,
I, PARAMV, false); }
Concurrenthashmap introduces the split (Segment), and the last line in the above code can actually be understood as splitting a large map into n small Hashtable, in the Put method, depending on the hash (Paramk.hashcode ()) To determine which Segment to store in, and if you look at the Segment put operation, we will find that the internal synchronization mechanism is based on the lock operation, so that you can lock part of the map (Segment). This effect is just going to put the same segment elements of the putting operation, to ensure synchronization, the lock is not the entire map (Hashtable is doing), compared to Hashtable improve the performance of multi-threaded environment, so Hashtable has been eliminated.
7. Comparison of HashMap and Concurrenthashmap
In the end, make a difference between the two brothers:
(1) After 4.2 analysis, we know that concurrenthashmap the entire bucket array segmentation (Segment), and then in each section with lock lock for protection, relative to the hashtable of the SYN keyword LOCK is more granular, Concurrent performance is better, while HashMap is not thread-safe without locking mechanism.
(2) HashMap's key value pairs allow NULL, but concurrenthashmap are not allowed.
So far the similarities and differences between HashMap, Hashtable and Concurrenthashmap are concluded.
Please respect the original, reprint please from the Source: http://blog.csdn.net/seu_calvin/article/details/52653711