Java containers HashMap and HashTable in detail
- 2020-06-23 00:21:58
- OfStack
1, HashMap
HashMap inherits the abstract class AbstractMap and implements the interfaces Map, Cloneable and Serializable. HashMap is a container for storing data in key-value pairs,
Consists of an array + linked list, where
key和value
Both can be null and key has a value of only 1.
HashMap
Non-thread-safe for key-value pairs
<
Key,Value
>
.
Internally, HashMap encapsulates it as a counterpart
Entry<Key,Value>
Object. The storage size of HashMap can be dynamically changed:
The stored procedure
There is one for each object
HashCode
According to the HashCode value, call the hash function, calculate 1 hash value, call the indexFor function according to the hash value, calculate the storage location in table, if the location already has a value, then store in the bucket corresponding to that location.
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
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;
}
public final int hash(Object k) {
int h = hashSeed;
if (0 != h && k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
}
h ^= k.hashCode();
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
public final int hashCode() {
return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue())
}
static int indexFor(int h, int length) {
// assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
return h & (length-1);
}
Get the value
First, the hash value is calculated according to the HashCode code of key, then the indexFor function is called to calculate the storage location of the entry object in table, and the entry object stored in the bucket corresponding to that location is traversed. If the hash value and key of the object are the same as those to be found, the object is returned.
public final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
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 != null && key.equals(k))))
return e;
}
return null;
}
Equal judgment of two map
public final boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry)o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
Reflexivity: For any non-null reference value x, ES57en.equals (x) should return true.
Symmetry: For any non-null reference values x and y, x.equals (y) should return true if and only if ES66en.equals (x) returns true.
Transitivity: For any non-null reference values x, y, and z, if x.equals (y) returns true and y.equals (z) returns
true, then ES90en.equals (z) should return true.
1 Allergenicity: Multiple calls to x. equals(y) always return true or false for any non-null reference values x and y, as long as on the object
The information used in the equals comparison has not been modified.
For any non-null reference value x, ES109en.equals (null) should return false.
Dynamic allocation of storage space
HashMap
The number of buckets, i.e
Entry[] table
The length of an array, since arrays are contiguous storage units in memory, is spatially expensive, but its random-access speed is
Java
The fastest in the set. We increase the number of barrels and decrease it
Entry<Key,Value>
The length of the linked list to increase the speed of reading data from HashMap. This is a classic space for time strategy.
But we can't just start
HashMap
Allocating too many buckets (i.e
Entry[] table
Array start should not be too large), because array is a continuous memory space, it is expensive to create, and we are not sure how much HashMap can actually use to allocate such a large space. To solve this problem, HashMap USES the dynamic allocation of buckets according to the actual situation.
To dynamically allocate the number of buckets, a tradeoff is required, and HashMap's tradeoff is as follows:
if HashMap The size of the > HashMap The capacity of the ( namely Entry[] table The size of the )* Load factor ( Experience value 0.75)
the HashMap In the Entry[] table Is expanded to the current capacity 1 Times; Then replace the previous bucket `Entry<Key,Value>` The list is reallocated to the buckets
The above HashMap capacity (that is, the size of Entry[] table) * loading factor (empirical 0.75) is the so-called threshold (threshold).
2, HashTable
HashTable inherits Dictionary class, implements Map, Cloneable,Serializable interface, does not allow key to be empty, adopts zipper method to implement similar to HashMap.
HashTable is thread-safe (but there is a static method in the Collections class: synchronizedMap(), which creates a thread-safe Map object through which we can synchronously access the potential HashMap and lock the entire map object. CurrentHashMap is thread-safe and locks buckets only, without affecting the operation of other buckets on the map object.
I hope this article will be helpful to you