Introduction to the expansion mechanism of HashMap, ArrayList, StringBuilder, and hashmaparraylist in JAVA
Some content in JAVA to be resized is summarized as follows:
Part 1:
HashMap <String, String> hmap = new HashMap <> ();
HashSet <String> hset = new HashSet <> ();
Hashtable <String, String> htable = new Hashtable <> ();
Part 2:
CopyOnWriteArrayList <String> coarray = new CopyOnWriteArrayList <> ();
ArrayList <String> array = new ArrayList <> ();
Vector <String> vec = new Vector <> ();
Part 3:
StringBuffer sb = new StringBuffer ();
StringBuilder sbu = new StringBuilder ();
First, analyze the following source code: (JDK1.8)
1. Initial capacity.
2. Expansion mechanism.
3. Comparison of the same type.
1.1 HashMap:
1. Initial capacity definition: The default value is 1 <4 (16 ). The maximum capacity is 1 <30.
/**
* The default initial capacity-MUST be a power of two.
*/
Static final int DEFAULT_INITIAL_CAPACITY = 1 <4; // aka 16
/**
* The maximum capacity, used if a higher value is implicitly specified
* By either of the constructors with arguments.
* MUST be a power of two <= 1 <30.
*/
Static final int MAXIMUM_CAPACITY = 1 <30;
2. The expansion loading factor is (0.75). The first critical point is when the number of elements in the HashMap is equal to the table array length * The loading Factor (16*0.75 = 12 ),
If the capacity exceeds the capacity limit, the capacity is expanded according to oldThr <1 (original length * 2.
/**
* The load factor used when none specified in constructor.
*/
Static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* Constructs an empty <tt> HashMap </tt> with the default initial capacity
* (16) and the default load factor (0.75 ).
*/
If (newCap = oldCap <1) <MAXIMUM_CAPACITY &&
OldCap> = DEFAULT_INITIAL_CAPACITY)
NewThr = oldThr <1; // double threshold
1.2 HashSet
I. Initial capacity definition: 16. Because constructing a HashSet is equivalent to creating a new HashMap and then taking the Key of the HashMap.
The expansion mechanism is the same as that of HashMap.
Public HashSet (Collection <? Extends E> c ){
Map = new HashMap <> (Math. max (int) (c. size ()/. 75f) + 1, 16 ));
AddAll (c );
}
Public HashSet (int initialCapacity ){
Map = new HashMap <> (initialCapacity );
}
1.3 Hashtable <String, String> htable = new Hashtable <> ();
Public class Hashtable <K, V>
Extends Dictionary <K, V>
I. Initial capacity definition: capacity (11 ).
/**
* Constructs a new, empty hashtable with a default initial capacity (11)
* And load factor (0.75 ).
*/
Public Hashtable (){
This (11, 0.75f );
}
Ii. Expansion loading Factor (0.75). If the length exceeds the default value (int) (11*0.75) = 8, the expansion is old * 2 + 1.
Int newCapacity = (oldCapacity <1) + 1;
Summary: differences between HashTable and HashMap
First, inheritance is different.
Public class Hashtable extends Dictionary implements Map
Public class HashMap extends actmap implements Map
Second:
Methods In Hashtable are synchronized, while those in HashMap are not synchronized by default. In a multi-thread concurrent environment, you can directly use
Hashtable, but if you want to use HashMap, you have to add synchronization.
Third, keys and values in Hashtable cannot contain null values.
In HashMap, null can be used as a key. Such a key has only one; one or more keys can correspond to null values. When the get () method returns null,
That is, the key does not exist in HashMap, or the corresponding value of the key is null. Therefore, the get () method cannot be used in HashMap to determine
Whether a key exists. Instead, use the containsKey () method to determine whether a key exists.
Fourth, the internal implementation of the two traversal methods is different.
Hashtable and HashMap both use Iterator. For historical reasons, Hashtable also uses the Enumeration method.
Fifth, HashTable directly uses the hashCode of the object. HashMap recalculates the hash value.
Sixth,
Hashtable and HashMap are two internal implementation methods: the initial size of the array and the method of resizing. In HashTable, the default size of the hash array is 11.
The formula is old * 2 + 1. In HashMap, the default size of the hash array is 16, and the increment is old * 2.
2.1 CopyOnWriteArrayList:
/**
* Creates an empty list.
*/
Public CopyOnWriteArrayList (){
SetArray (new Object [0]);
}
CopyOnWriteArrayList creates a new array every time it is modified, and then replaces the original array with the new array.
. Therefore, you can still perform read operations to read the original array operated directly during the modification operation. Read and Write operations have different objects. Therefore, read operations and write operations interact with each other.
No interference. Only synchronization and waiting between writing and writing are required. In addition, the original array is declared as volatile, which ensures that, once the array changes
Other threads (read threads and Other write threads) are visible.
CopyOnWriteArrayList does not specify the default initial capacity like ArrayList. It does not have an automatic resizing mechanism. Instead, it adds several elements with the same length.
The expected growth.
CopyOnWriteArrayList is suitable for reading, writing, and resizing. And each time the modification operation generates a new array, it means
With the new capacity set, it is equivalent to resizing, so no additional mechanism is required to achieve resizing.
2.2 ArrayList <String> array = new ArrayList <> ();
I. Initial capacity definition: 10.
/**
* Default initial capacity.
*/
Private static final int DEFAULT_CAPACITY = 10;
Ii. Scale-out: oldCapacity + (oldCapacity> 1), that is, 1.5 times the length of the original set.
// Overflow-conscious code
Int oldCapacity = elementData. length;
Int newCapacity = oldCapacity + (oldCapacity> 1 );
2.3 Vector <String> vec = new Vector <> ();
I. Initial capacity definition: 10.
Public Vector (){
This (10 );
}
2. Expansion: When the expansion factor is greater than 0, the length of the new array is the length of the original array + Expansion Factor. Otherwise, the length of the new array is twice the length of the original array.
// Overflow-conscious code
Int oldCapacity = elementData. length;
Int newCapacity = oldCapacity + (capacityIncrement> 0 )?
CapacityIncrement: oldCapacity );
Summary:
1. The initial capacity of ArrayList and Vector is 10.
2. The expansion mechanism is different. When the current length is exceeded, the ArrayList extension is 1.5 times that of the original one. If the expansion factor Vector extension is not considered, it is twice that of the original one.
3. ArrayList is non-thread-safe, and the processing efficiency is faster than that of Vector. If thread security and efficiency are both considered, CopyOnWriteArrayList can be used.
3.1 StringBuffer sb = new StringBuffer ();
I. Initial capacity definition: 16.
Public StringBuffer (){
Super (16 );
}
Public final class StringBuffer
Extends AbstractStringBuilder
Implements java. io. Serializable, CharSequence
Ii. Resizing: Because StringBuffer extends actstringbuilder, we actually use AbstractStringBuilder.
When append (str) is used to add a string, assume that the string contains a string of count characters and the initial length is value = 16.
String length (count + str. length () <= (value * 2 + 2) is expanded by value * 2 + 2 length, and
Value = value * 2 + 2. If (count + str. length ()> (value * 2 + 2), expand the capacity according to the length of count + str. length () and
Value = count + str. length (). Compare the above method with value * 2 + 2 when the next time exceeds the limit.
Private int newCapacity (int minCapacity ){
// Overflow-conscious code
Int newCapacity = (value. length <1) + 2;
If (newCapacity-minCapacity <0 ){
NewCapacity = minCapacity;
3.2 StringBuilder sbu = new StringBuilder ();
Public final class StringBuilder
Extends AbstractStringBuilder
Implements java. io. Serializable, CharSequence
Public StringBuilder (){
Super (16 );
}
Private int newCapacity (int minCapacity ){
// Overflow-conscious code
Int newCapacity = (value. length <1) + 2;
If (newCapacity-minCapacity <0 ){
NewCapacity = minCapacity;
Summary:
1. StringBuilder was introduced by jdk1.5, and StringBuffer was available in 1.0;
2. Both StringBuilder and StringBuffer are variable strings. You can use append or insert to modify the content of a string;
3. StringBuffer is thread-safe, but StringBuilder is not. Therefore, StringBuffer is preferred in a multi-threaded environment.
StringBuilder, because it is faster.
4. Both StringBuilder and StringBuffer inherit from the AbstractStringBuilder class. AbStractStringBuilder mainly implements resizing, append,
Insert method. The parent class directly called by the related methods of StrngBuilder and StringBuffer.
5. The initial capacity of StringBuilder and StringBuffer is 16. You should set the initial value manually. To avoid performance problems caused by multiple resizing operations;
6. the resizing mechanism of StringBuilder and StringBuffer is as follows: First, try to expand the current array capacity to 2 times of the original array capacity plus 2. Suppose this new capacity
If the volume is still less than the predefined minimum value (minimumCapacity), the new capacity is set to (minimumCapacity), and whether the new capacity is exceeded,
Set the capacity to the maximum integer value 0x7fffffff.