Java Collections Framework Analysis (four) HashMap analysis

This article mainly analyze the Map part of the Java Collections Framework, HashMap, the source code analysis based on JDK1.8, inadequate analysis tools, AndroidStudio, articles Analysis Branch, please forgive me!

About HashMap

A Map interface hash table-based object storage is a key object (Entry <K, V>); is worth noting that HashMap is not thread-safe, if you want to HashMap thread-safe, can Collections class synchronizedMap static method to obtain thread-safe HashMap.

Map map = Collections.synchronizedMap(new HashMap());
复制代码

data structure

Java basic data structure arrays and linked lists. Features of the array is spatially continuous (fixed size), addressed quickly, but need to move the insertion and deletion of elements, the query faster, increasing slowly deleted. List the contrary, it can dynamically increase or decrease the space to accommodate new and delete elements, but only to find when looking down a node, so the increase in fast delete, search slow. Is there a structure combines the advantages of an array and a linked list it? Of course, that is a hash table (although it is a comprehensive advantage, but certainly not in fact find an array of fast, not as fast as insert delete the list, a compromise way, right), all data structures can use these two basic structure be constructed, HashMap is no exception. HashMap is actually a "hash list" data structure, i.e., a combination of arrays and lists.

Backing HashMap is mainly based arrays and linked lists implemented reason it fairly quickly query speed mainly because it is determined by the position of the stored hash code is calculated. HashMap is mainly hashCode key calculated by the hash value, as long as the same as the hashCode, the calculated hash value is the same. If the stored objects more, it is possible to calculate the different objects out of the hash values ​​are the same, which appeared in the so-called hash collision. Studied the data structure of the students know that there are many ways to resolve hash collision, HashMap underlying hash is to resolve conflict through the list. FIG., Which represents the left part of the hash table, also called a hash array, each element of the array is a single-head node of the linked list, the linked list is used to resolve the conflict, if a different key is mapped to the same location of the array at which it will be placed in a single list.

Internal interface

Internal interface EntryEntry interface is an internal interface defined in the Map

 interface Entry<K, V> {
	K getKey();
	V getValue();
	V setValue(V value);
	boolean equals(Object o);
	int hashCode();
	public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K, V>> comparingByKey() {
		return (Comparator<Map.Entry<K, V>> & Serializable) (c1, c2) -> c1.getKey().compareTo(c2.getKey());
	}
	public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K, V>> comparingByValue() {
		return (Comparator<Map.Entry<K, V>> & Serializable) (c1, c2) -> c1.getValue().compareTo(c2.getValue());
	}
	public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
		Objects.requireNonNull(cmp);
		return (Comparator<Map.Entry<K, V>> & Serializable) (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
	}
	public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
		Objects.requireNonNull(cmp);
		return (Comparator<Map.Entry<K, V>> & Serializable) (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
	}
}
复制代码

For HashMap, its internal realization inside a static inner classes, namely HashMapEntry <K, V>, its important attributes are key, value, next, from property key, value we can very clearly see that HashMap key HashMapEntry value for a basic bean implementation, and above us when it comes to basic HashMap is a linear array, the array is HashMapEntry [], Map contents inside are kept in HashMapEntry [] inside.

transient HashMapEntry<K,V>[] table = (HashMapEntry<K,V>[]) EMPTY_TABLE;
复制代码

We can analyze this simple static inner classes HashMapEntry.java

// HashMapEntry.java静态内部类,实现的HashMap线性数组   
static class HashMapEntry<K, V> implements Map.Entry<K, V> {
	// key,value值
	final K key;
	V value;
	// 每个数组里面包含的链表
	HashMapEntry<K, V> next;
	int hash;
	/** * 构造函数 * 输入参数包括"哈希值(h)", "键(k)", "值(v)", "下一节点(n)" */
	HashMapEntry(int h, K k, V v, HashMapEntry<K, V> n) {
		value = v;
		next = n;
		key = k;
		hash = h;
	}
	public final K getKey() {
		return key;
	}
	public final V getValue() {
		return value;
	}
	public final V setValue(V newValue) {
		V oldValue = value;
		value = newValue;
		return oldValue;
	}
	/**
	 * * 判断两个Entry是否相等 * 若两个Entry的“key”和“value”都相等,则返回true。 * 否则,返回false
	 */
	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;
	}
	public final int hashCode() {
		return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
	}
	public final String toString() {
		return getKey() + "=" + getValue();
	}
	/**
	 * * 当向HashMap中添加元素时,会调用recordAccess()
	 */
	void recordAccess(HashMap<K, V> m) {
	}
	/**
	 * * 当从HashMap中删除元素时,会调用recordRemoval()。
	 */
	void recordRemoval(HashMap<K, V> m) {
	}
}
复制代码

HashMapEntry array is actually a HashMap, HashMapEntry objects contain the keys and values, which is a next HashMapEntry object that is used to handle hash conflicts, forming a linked list. We have analyzed the basic structure, then we start the topic, beginning HashMap analysis of source code to achieve it!

Source code analysis

Affirming class

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
复制代码

First, we look at some property of internal HashMap stated,

//属性申明	
//默认的初始容量,必须是2的幂次方。    
static final int DEFAULT_INITIAL_CAPACITY = 4;    
//最大容量,默认为2的30次方,    
static final int MAXIMUM_CAPACITY = 1 << 30;    
//加载因子    
static final float DEFAULT_LOAD_FACTOR = 0.75f;    
//    
static final HashMapEntry<?,?>[] EMPTY_TABLE = {};    
//数组表,大小可以改变,且大小必须为2的幂    
transient HashMapEntry<K,V>[] table = (HashMapEntry<K,V>[]) EMPTY_TABLE;    
//当前Map中key-value映射的个数    
transient int size;    
//当实际大小超过临界值时,会进行扩容threshold = 加载因子*容量    
int threshold;    
//加载因子    
final float loadFactor = DEFAULT_LOAD_FACTOR;    
//Hash表结构性修改次数    
transient int modCount;
复制代码

For load factor loadFactor, we could make a little explanation:

The load factor is a degree loadFactor filled Hsah elements in the table.

The more the greater the load factor, filled elements, benefit is high space utilization, but:: If the chance of conflict will increase the length of the list getting longer and longer, lower search efficiency. On the contrary, the smaller the load factor, the less filled elements, the benefits are: reduces the chance of conflict, but: more than a waste of space data in the table will be too sparse (not with a lot of space, the expansion began). the greater the chance of conflict, the higher the costs are looking for. Therefore, we must find a balance and compromise between the "conflict opportunities" and "space utilization." is a data structure known on this balance and compromise nature "when - empty" contradictory balance and compromise.

If the machine enough memory, and you want to speed up the search, then you can the load factor a little; the contrary if the machine memory is tight, and there is no requirement for speed, then you can query the load factor bigger. But in general we do not take up set it up, take it like a default value of 0.75. Some of the above basic properties are stated in the HashMap, and if you do not understand what it means, you can wait until later look at. We then analyze the code below.

Constructor

Then we analysis HashMap constructor

/**     
 * * 设置初始容量大小以及加载因子     
 * *     
 * * @param  initialCapacity the initial capacity     
 * * @param  loadFactor      the load factor     
 * * @throws IllegalArgumentException if the initial capacity is negative     
 * *         or the load factor is nonpositive     
 * */    
public HashMap(int initialCapacity, float loadFactor) {
	//初始容量大小在[DEFAULT_INITIAL_CAPACITY,MAXIMUM_CAPACITY]之间        
	if (initialCapacity < 0)           
		throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
	if (initialCapacity > MAXIMUM_CAPACITY) {
		initialCapacity = MAXIMUM_CAPACITY;       
		} 
	else if (initialCapacity < DEFAULT_INITIAL_CAPACITY) { 
		initialCapacity = DEFAULT_INITIAL_CAPACITY;       
		}       
	if (loadFactor <= 0 || Float.isNaN(loadFactor)) 
		throw new IllegalArgumentException("Illegal load factor: " +   
    loadFactor);               
	threshold = initialCapacity; 
	init();   
	}    
/** 
 *     
 *     * 设置初始容量,加载因子为默认的0.75     
 *     * @param  initialCapacity the initial capacity.     
 *     * @throws IllegalArgumentException if the initial capacity is negative.     
 *     */    
public HashMap(int initialCapacity) {
	this(initialCapacity, DEFAULT_LOAD_FACTOR);    
	}   
/** 
 *     * 使用默认的容量大小和加载因子     
 *     */   
public HashMap() { 
	this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);    
	}    
/** 
 *     * 根据指定的map生成一个新的HashMap,负载因子使用默认值,
 *     初始容量大小为Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,DEFAULT_INITIAL_CAPACITY)     
 *     *     
 *     * @param   m the map whose mappings are to be placed in this map     
 *     * @throws  NullPointerException if the specified map is null    
 *      */    
public HashMap(Map<? extends K, ? extends V> m) {  
	this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,  DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);		
	//初始化HashMapEntry数组        
	inflateTable(threshold);       
	putAllForCreate(m);    
	}
}
复制代码

Through the above four HashMap constructor we can see that we can set the size of the initial capacity and load factor, or directly through a HashMap to construct a map, wherein the size of our initial capacity is set to 4, it must be a power of two while it is in the range between 4 and 2 to the 30th power. The constructor is simple, nothing can be analyzed, then we focus on adding and analyze HashMap acquisition method, that is, put and get methods.

PUT data storage

//向map存入一个键值对,如果key已存在,则覆盖
public V put(K key, V value) {
	//如果HashMapEntry数组为空,则重新初始化一下        
	if (table == EMPTY_TABLE) {
		inflateTable(threshold);        
		}		
	//对key为null的键值对调用putForNullKey处理
	if (key == null)            
		return putForNullKey(value);
	//生成hash值        
	int hash = sun.misc.Hashing.singleWordWangJenkinsHash(key);
	//生成hash值索引        
	int i = indexFor(hash, table.length);
	//循环遍历Entry数组,若“该key”对应的键值对已经存在,则用新的value取代旧的value。然后退出,同时返回旧的value!        
	for (HashMapEntry<K,V> e = table[i]; e != null; e = e.next) {
		Object k;			
		//如果找到了相同的key,则覆盖旧的value
		if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 
			V oldValue = e.value;                
			e.value = value;                
			//调用HashMapEntry增加这个Entry                
			e.recordAccess(this);                
			return oldValue;            
			}        
		}				
	//修改次数        
	modCount++;        
	//将key-value添加到table[i]处,也就是在链表的头部插入一个数据<k,v>        
	addEntry(hash, key, value, i);        
	return null;    
	}
}
复制代码

Above about the content is, to obtain the hash value of the key, and acquires the position in the array based on the hash value, it is determined whether there is the key in the table [i], that is the first loop through the list, if it finds the key value , then replaces the key value, and then modify the value inside, if the key can not be found in the list, then data is inserted at the head of a linked list. In the put method, we detail some of the methods of analysis. At the beginning of the array is determined whether there is a null operation

//如果HashMapEntry数组为空,则重新初始化一下        
if (table == EMPTY_TABLE) {
	inflateTable(threshold);
	}	
/**
 *      
 *      * 初始化这个数组     
 *      */    
private void inflateTable(int toSize) { 
	// 寻找大于toSize的2的幂次方的最小值        
	int capacity = roundUpToPowerOf2(toSize);
	float thresholdFloat = capacity * loadFactor;       
	if (thresholdFloat > MAXIMUM_CAPACITY + 1) { 
		thresholdFloat = MAXIMUM_CAPACITY + 1;        
		}				
	//初始化数组        
	threshold = (int) thresholdFloat;
	table = new HashMapEntry[capacity];    
	}
}
复制代码

Next, it is judged whether the key is null, if the operation is a null, then perform putForNullKey (V value)

/**     
 * * 插入key为null的值,在数组的第一个位置进行插入操作     
 * */    
private V putForNullKey(V value) {
	//循环遍历数组第一个数组的链表,如果存在null的则进行覆盖更新操作        
	for (HashMapEntry<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++;        
	//链表中不存在key为null的值,则在链表的开头插入这个key为null的值        
	addEntry(0, null, value, 0);       
	return null;    
	}
}
复制代码

If the key is null, then, hash value is 0, the object is stored in the array index 0 position. That table [0], then we analyze addEntry method,

//通过hash值来算出在table中哪个位置,然后进行插入操作
void addEntry(int hash, K key, V value, int bucketIndex) {
	//        
	if ((size >= threshold) && (null != table[bucketIndex])) {
		//数组扩容            
		resize(2 * table.length);            
		//如果key为null的话,那么hash值为0,也就是在数组的第一个位置,即table[0]位置            
		hash = (null != key) ? sun.misc.Hashing.singleWordWangJenkinsHash(key) : 0;            
		//根据hash的值来算出在数组的中位置            
		bucketIndex = indexFor(hash, table.length);        
	}		
	//数据插入或者更新操作        
	createEntry(hash, key, value, bucketIndex);    
}
复制代码

We calculated hash value table value in the table, then proceed to analyze methods createEntry

//数据操作,在链表头部插入一个数组,这就是在一个链表头部插入一个节点的过程。获取table[i]的对象e,将table[i]的对象修改为新增对象,让新增对象的next指向e。
void createEntry(int hash, K key, V value, int bucketIndex) {
	//保存table[i]的对象为e        
	HashMapEntry<K,V> e = table[bucketIndex];        
	//然后将table[i]的值修改为新增的对象,并将新增对象的next值设置为原先table[i]的值e,这就相当于在链表头部插入一个数据了。        
	table[bucketIndex] = new HashMapEntry<>(hash, key, value, e);        
	size++;   
	}
}
复制代码

Analysis of the situation over the key is null, then we analyze the key is not equal to null situation. Subsequently, we calculated by the hash key, and then calculates the position of the array in a table according to the value of the hash int i = indexFor (hash, table.length);

//  indexFor返回hash值和table数组长度减1的与运算结果。为什么使用的是length-1?应为这样可以保证结果的最大值是length-1,不会产生数组越界问题。
static int indexFor(int h, int length) {
	return h & (length-1);   
}
复制代码

We found a table in the rear position in the array, we began to traverse the current position in the list, and if there is then covered key operation does not exist, then insert the data in a linked list head. The above is a complete operational data increase, here we summarize the central idea. First, we need to increase the data we determined whether the key is null, if null, then at the first position in the array, i.e. table [0] at the insert or update operations (if present in the chain at a first position key not null data, then the update operation is covered, if not present, then insert the data in a list head, is a common chain insert), followed by left key is not equal to null this step, we need to key after the calculated hash value, and secondly, the need to calculate the hash value in accordance with a position in the table, the position obtained, we repeat the operation in the linked list (update found to cover not find a header is inserted in the list data), which is the HashMap put operation.

We generally hash to the hash table will naturally think of using modulo hash value length (i.e., hashing division), the Hashtable is also achieved, this method can guarantee the basic elements of the hash in the hash table more uniform, but will use the modulo division operation efficiency is very low, in the HashMap instead through h & modulo method (length-1), also achieving uniform hash, but the efficiency is much higher, which is HashMap an improvement over the Hashtable. Next, we analyze why the capacity of the hash table, if under certain integer power of 2. First, length is an integer power of 2, then, h & (length-1) is equivalent to the length modulus, this will ensure the uniformity of the hash, but also improves the efficiency; secondly, length is an integer power of two, then , is an even number, so length-1 is odd, odd last digit is 1, this will ensure the h & (length-1) may be the last bit is 0, it may be (depending on the value of h) 1, i.e., result after may be an even number, may also be an odd number, so that they can ensure the uniformity of the hash, and if the length is odd, then, obviously length-1 is an even number, it is the last bit is 0, so that h & ( length-1) is the last one definitely is 0, that can only be an even number, so that any hash value will only be hashed even-index position in the array on which they wasted nearly half the space, therefore, length take integer power of 2, hash values ​​are different in order to make the probability of collision is small, so that the elements can be uniformly hash in the hash table. Finished put analysis methods, then we analyze putAll method,

/**     
 * * @param m mappings to be stored in this map     
 * * @throws NullPointerException if the specified map is null     
 * */    
public void putAll(Map<? extends K, ? extends V> m) { 
	int numKeysToBeAdded = m.size();        
	if (numKeysToBeAdded == 0)            
		return;        
	if (table == EMPTY_TABLE) {
		inflateTable((int) Math.max(numKeysToBeAdded * loadFactor, threshold));        
		}        /*         */        
	if (numKeysToBeAdded > threshold) {  
		int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);          
		if (targetCapacity > MAXIMUM_CAPACITY)                
			targetCapacity = MAXIMUM_CAPACITY;            
		int newCapacity = table.length;           
		while (newCapacity < targetCapacity)               
			newCapacity <<= 1;           
		if (newCapacity > table.length)                
			resize(newCapacity);        
		}		
	//遍历m中的内容,然后调用put方法将元素添加到table数组中        
	for (Map.Entry<? extends K, ? extends V> e : m.entrySet())            
		put(e.getKey(), e.getValue());   
	}
}
复制代码

Traversal when it comes to the entrySet method, which is defined in the Map interface, HashMap is also achieved. We have a HashMap constructor method called putAllForCreate method, analyze the content.

private void putAllForCreate(Map<? extends K, ? extends V> m) {        
    for (Map.Entry<? extends K, ? extends V> e : m.entrySet())                            
    	putForCreate(e.getKey(), e.getValue());    
}
复制代码

Look at this method name to know about the meaning, in HashMap initialization of a map all assigned to the initial value. Code is, first traverse it Map, and then in turn added to it, we enter putForCreate specific method View source

private void putForCreate(K key, V value) {
	//获取key的hash值        
	int hash = null == key ? 0 : sun.misc.Hashing.singleWordWangJenkinsHash(key);        
	//根据hash值来计算在table中的位置        
	int i = indexFor(hash, table.length);        
	//循环遍历数组下标为i的链表,如果存在则覆盖更新,也就是上面计算出来的table中的位置        
	for (HashMapEntry<K,V> e = table[i]; e != null; e = e.next) {            
		Object k;            
		if (e.hash == hash &&                
				((k = e.key) == key || (key != null && key.equals(k)))) { 
			e.value = value;                
			return;            
			}       
		}		
	//当前数组中的位置链表中不存在,则在链表头部插入一条数据        
	createEntry(hash, key, value, i);    
	}
}
复制代码

The method calculates a hash value needs to be added to the element table and index i in the array. Then traversing table [i] in the list, if the value of the key elements pass key values ​​are equal, then the replacement value, the method ends. If there is the same key value element, the call createEntry create and add elements. Continue into the process View source createEntry

void createEntry(int hash, K key, V value, int bucketIndex) {
	HashMapEntry<K,V> e = table[bucketIndex];        
	table[bucketIndex] = new HashMapEntry<>(hash, key, value, e);        
	size++;   
}
复制代码

This method is relatively simple, is inserted into the head of a linked list data, putAllForCreate put methods analogous methods. So far all related operations are put to explain finished. Outside put, the other common operations is get, get the following method to look at.

get method

Compared to put the method, get method is relatively simple, we have to look at specific implementation.

 
public V get(Object key) { 
	if (key == null)            
		return getForNullKey();       
	Entry<K,V> entry = getEntry(key);        
	return null == entry ? null : entry.getValue();   
}
复制代码

First, determine whether the key is equal to null, then it would get equal value from getForNullKey (), if not equal, then get through getEntry. We first look at the situation of equal null.

private V getForNullKey() {
	if (size == 0) {
		return null;        
	}        
	for (HashMapEntry<K,V> e = table[0]; e != null; e = e.next) {
		if (e.key == null)                
			return e.value;        
		}        
	return null;    
}
复制代码

If the current table size is 0, then, it will return null, if not empty, then at the array table [0] in the list circulated match, find null key for the list node, if found, the process directly returns value, otherwise return null, very simple. Then we analyze the key is not equal to null the circumstances, that is, into getEntry method of analysis.

final Entry<K,V> getEntry(Object key) {
	if (size == 0) {
		return null;        
	}        
	int hash = (key == null) ? 0 : sun.misc.Hashing.singleWordWangJenkinsHash(key);        
	for (HashMapEntry<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;    
}
复制代码

We have analyzed the put method, so that the code inside substantially similar, very simple, first to obtain the hash value, and then acquires the index table in the table [I] according to the hash value, secondly to loop through according to this array location table [i] in the list, it is determined whether or not there exists the entry, if the return value, the absence of null is returned. The above is the more important of the two HashMap method, a put, a get, we have all the analysis done, then we analyze the method to the rest of the rest.

remove method

Analysis done put, get method, then analyze the remove method.

public V remove(Object key) {
	Entry<K,V> e = removeEntryForKey(key);        
	return (e == null ? null : e.getValue());    
}
复制代码

In the remove method, called a removeEntryForKey approach, we then take a look,

final Entry<K,V> removeEntryForKey(Object key) {
	//如果数组为空,直接返回null        
	if (size == 0) { 
		return null;        
	}        
	//获取需要移除的key的hash值        
	int hash = (key == null) ? 0 : sun.misc.Hashing.singleWordWangJenkinsHash(key);        
	//获取在数组table[i]中的索引值i        
	int i = indexFor(hash, table.length);        
	//保存当前数组中的第一个链表节点        
	HashMapEntry<K,V> prev = table[i];        
	HashMapEntry<K,V> e = prev;        
	while (e != null) {            
		HashMapEntry<K,V> next = e.next;            
		Object k;            
		if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) {
			modCount++;                
			size--;                
			if (prev == e)                   
				table[i] = next;                
			else                    
				prev.next = next;                
			e.recordRemoval(this);                
			return e;            
			}            
		//单链表删除操作            
		prev = e;            
		e = next;        
		}        
	return e;    
	}
}
复制代码

The above process is to first find the index table corresponding to the array, and then is similar in general operation to delete the list, a singly linked list and deleting nodes, is very simple. In the C language is to modify the pointer, this case is going to delete a node before the next point to delete the next node can be deleted.

The remaining method

The above analysis of most of the code HashMap, as well as some of the more important given the way we interpret a one-time, not one to do the analysis.

Clear map

/**     
 * * 清空map     
 * */    
public void clear() {
	modCount++;        
	Arrays.fill(table, null); 
	size = 0;   
	} 
复制代码

** determine whether there is a specified value **

/**     
 * * 判断是否存在指定的value     
 * *     
 * * @param value value whose presence in this map is to be tested     
 * * @return <tt>true</tt> if this map maps one or more keys to the     
 * *         specified value     
 * */    
public boolean containsValue(Object value) {
	if (value == null)            
		return containsNullValue();        
	HashMapEntry[] tab = table;        
	for (int i = 0; i < tab.length ; i++)            
		for (HashMapEntry e = tab[i] ; e != null ; e = e.next)
			if (value.equals(e.value))                    
				return true;        
	return false;    
}  
复制代码

Loop through the array, the array is determined table [i] lists the following node if there is equal to null value

/**     
 * * 循环遍历数组,判断数组table[i]下面的链表是否存在value等于null的节点     
 * */    
private boolean containsNullValue() {
	HashMapEntry[] tab = table;        
	for (int i = 0; i < tab.length ; i++)           
		for (HashMapEntry e = tab[i] ; e != null ; e = e.next)
			if (e.value == null)                    
				return true;        
	return false;    
}    

复制代码

** ** For shallow copy of the HashMap

/**    
 *  * 针对HashMap的浅复制     
 *  *     
 *  * @return a shallow copy of this map     
 *  */    
public Object clone() {
	HashMap<K,V> result = null;        
	try {            
		result = (HashMap<K,V>)super.clone();        
		} 
	catch (CloneNotSupportedException e) { 
		// assert false;        
		}       
	if (result.table != EMPTY_TABLE) { 
		result.inflateTable(Math.min(  (int) Math.min( size * Math.min(1 / loadFactor, 4.0f), 
				// we have limits...                    
				HashMap.MAXIMUM_CAPACITY),              
				table.length));        
		}        result.entrySet = null;
		result.modCount = 0;        
		result.size = 0;        
		result.init();       
		result.putAllForCreate(this);
		return result;    
		}
	}
}
复制代码

The above is probably HashMap source, which also involves the concept of entrySet, which is also involved in other collections framework, it is going to say together herein, this description yet. Stay tuned for future articles. If wrong, kindly correct me, thank you! Finally, we write a simple test to learn about HashMap common law.

package MapDemo;
import java.util.HashMap;
import java.util.Map;
public class HashMapTest {
	public static void main(String[] args) {
		
		Map<String, String> mHashMap=new HashMap<String,String>();
		mHashMap.put("A", "AAAAAAAA...");
		mHashMap.put("B", "BBBBBBBB...");
		mHashMap.put("C", "CCCCCCCC...");
		mHashMap.put("D", "DDDDDDDD...");
		mHashMap.put("E", "EEEEEEEE...");
		mHashMap.put("F", "FFFFFFFF...");
		mHashMap.put("G", "GGGGGGGG...");
		mHashMap.put("H", "HHHHHHHH...");
		mHashMap.put("I", "IIIIIIII...");
		
		//打印HashMap
		System.out.println("mHashMap: "+mHashMap);
		
		//打印HashMap的size
		System.out.println("mHashMap size is: "+mHashMap.size());
		
		//判断HashMap中是否存在A的key,结果为TRUE
		System.out.println("mHashMap is containsKey of A:"+ mHashMap.containsKey("A"));
		
		//判断HashMap中是否存在IIIIIIII的value,结果为FALSE
		System.out.println("mHashMap is containsValue of IIIIIIII:"+ mHashMap.containsValue("IIIIIIII"));
		
		//打印HashMap中的key
		System.out.print("the key of mHashMap is :");
		for (String string : mHashMap.keySet()) {
			System.out.print("   "+string);
		}
		System.out.println();
		
		//打印HashMap中的value
		System.out.print("the value of mHashMap is :");
		for (String string : mHashMap.values()) {
			System.out.print("   "+string);
		}
		System.out.println();
		//打印key-value集合
		System.out.println("key-value集合:");
		for (Map.Entry<String, String> entry : mHashMap.entrySet()) {
			System.out.println("key: "+entry.getKey()+" value: "+entry.getValue());
		}
	}
}
复制代码

Output

mHashMap: {A=AAAAAAAA..., B=BBBBBBBB..., C=CCCCCCCC..., D=DDDDDDDD..., E=EEEEEEEE..., F=FFFFFFFF..., G=GGGGGGGG..., H=HHHHHHHH..., I=IIIIIIII...}
mHashMap size is: 9
mHashMap is containsKey of A:true
mHashMap is containsValue of IIIIIIII:false
the key of mHashMap is :   A   B   C   D   E   F   G   H   I
the value of mHashMap is :   AAAAAAAA...   BBBBBBBB...   CCCCCCCC...   DDDDDDDD...   EEEEEEEE...   FFFFFFFF...   GGGGGGGG...   HHHHHHHH...   IIIIIIII...
key-value集合:
key: A value: AAAAAAAA...
key: B value: BBBBBBBB...
key: C value: CCCCCCCC...
key: D value: DDDDDDDD...
key: E value: EEEEEEEE...
key: F value: FFFFFFFF...
key: G value: GGGGGGGG...
key: H value: HHHHHHHH...
key: I value: IIIIIIII...
复制代码

About the Author

Focus on Android development for many years, likes to write blog records summarize learning experience, synchronized updates on my blog public number, welcome everyone's attention, we can talk about ~

Here Insert Picture Description

Guess you like

Origin juejin.im/post/5dbad16bf265da4cfb512701