HashMap(java7)
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {}
从上面的源码可以看出来,hashMap继承了AbstractMap<K,V>的抽象类,实现了Map<K,V>的接口。
1 /** 2 * Hash table based implementation of the <tt>Map</tt> interface. This 3 * implementation provides all of the optional map operations, and permits 4 * <tt>null</tt> values and the <tt>null</tt> key. (The <tt>HashMap</tt> 5 * class is roughly equivalent to <tt>Hashtable</tt>, except that it is 6 * unsynchronized and permits nulls.) This class makes no guarantees as to 7 * the order of the map; in particular, it does not guarantee that the order 8 * will remain constant over time. 9 * 10 * <p>This implementation provides constant-time performance for the basic 11 * operations (<tt>get</tt> and <tt>put</tt>), assuming the hash function 12 * disperses the elements properly among the buckets. Iteration over 13 * collection views requires time proportional to the "capacity" of the 14 * <tt>HashMap</tt> instance (the number of buckets) plus its size (the number 15 * of key-value mappings). Thus, it‘s very important not to set the initial 16 * capacity too high (or the load factor too low) if iteration performance is 17 * important. 18 * 19 * <p>An instance of <tt>HashMap</tt> has two parameters that affect its 20 * performance: <i>initial capacity</i> and <i>load factor</i>. The 21 * <i>capacity</i> is the number of buckets in the hash table, and the initial 22 * capacity is simply the capacity at the time the hash table is created. The 23 * <i>load factor</i> is a measure of how full the hash table is allowed to 24 * get before its capacity is automatically increased. When the number of 25 * entries in the hash table exceeds the product of the load factor and the 26 * current capacity, the hash table is <i>rehashed</i> (that is, internal data 27 * structures are rebuilt) so that the hash table has approximately twice the 28 * number of buckets. 29 * 30 * <p>As a general rule, the default load factor (.75) offers a good tradeoff 31 * between time and space costs. Higher values decrease the space overhead 32 * but increase the lookup cost (reflected in most of the operations of the 33 * <tt>HashMap</tt> class, including <tt>get</tt> and <tt>put</tt>). The 34 * expected number of entries in the map and its load factor should be taken 35 * into account when setting its initial capacity, so as to minimize the 36 * number of rehash operations. If the initial capacity is greater 37 * than the maximum number of entries divided by the load factor, no 38 * rehash operations will ever occur. 39 * 40 * <p>If many mappings are to be stored in a <tt>HashMap</tt> instance, 41 * creating it with a sufficiently large capacity will allow the mappings to 42 * be stored more efficiently than letting it perform automatic rehashing as 43 * needed to grow the table. 44 * 45 * <p><strong>Note that this implementation is not synchronized.</strong> 46 * If multiple threads access a hash map concurrently, and at least one of 47 * the threads modifies the map structurally, it <i>must</i> be 48 * synchronized externally. (A structural modification is any operation 49 * that adds or deletes one or more mappings; merely changing the value 50 * associated with a key that an instance already contains is not a 51 * structural modification.) This is typically accomplished by 52 * synchronizing on some object that naturally encapsulates the map. 53 */
然后我们再看一下,HashMap的组成,主要的是实现方法为put和get方法,主要的参数有capacity(桶的容量)和load factor(加载因子)。上面是官网的描述,大致意思为:
1、HashMap实现了Map的接口,<K,V>对中的key和value都可以为空,除了不是线程安全的和允许为null外,几乎是与HashTable一样的。同时也不能保证其的顺序。
2、一个hashmap对象主要有两个参数capacity(桶的容量)和load factor(加载因子),默认load factor为0.75是在时间和空间上性能最优的。
1 /** 2 * Constructs an empty <tt>HashMap</tt> with the default initial capacity 3 * (16) and the default load factor (0.75). 4 */ 5 public HashMap() { 6 this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); 7 }
上面的是不带参数的HashMap的构造器,也是我们创建对象的时候经常使用的,默认数组或者桶的容量为16,加载因子为0.75。
1 /** 2 * Constructs an empty <tt>HashMap</tt> with the specified initial 3 * capacity and the default load factor (0.75). 4 * 5 * @param initialCapacity the initial capacity. 6 * @throws IllegalArgumentException if the initial capacity is negative. 7 */ 8 public HashMap(int initialCapacity) { 9 this(initialCapacity, DEFAULT_LOAD_FACTOR); 10 }
我们也可以自定义数组的容量,加载因子默认为0.75。
/** * Constructs an empty <tt>HashMap</tt> with the specified initial * capacity and load factor. * * @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) { 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); this.loadFactor = loadFactor; threshold = initialCapacity; init(); }
同时也可以既修改容量有修改加载因子,但是最好不要修改。
1 /** 2 * Associates the specified value with the specified key in this map. 3 * If the map previously contained a mapping for the key, the old 4 * value is replaced. 5 * 6 * @param key key with which the specified value is to be associated 7 * @param value value to be associated with the specified key 8 * @return the previous value associated with <tt>key</tt>, or 9 * <tt>null</tt> if there was no mapping for <tt>key</tt>. 10 * (A <tt>null</tt> return can also indicate that the map 11 * previously associated <tt>null</tt> with <tt>key</tt>.) 12 */ 13 public V put(K key, V value) { 14 if (table == EMPTY_TABLE) { 15 inflateTable(threshold); 16 } 17 if (key == null) 18 return putForNullKey(value); 19 int hash = hash(key); 20 int i = indexFor(hash, table.length); 21 for (Entry<K,V> e = table[i]; e != null; e = e.next) { 22 Object k; 23 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 24 V oldValue = e.value; 25 e.value = value; 26 e.recordAccess(this); 27 return oldValue; 28 } 29 } 30 31 modCount++;// 32 addEntry(hash, key, value, i); 33 return null; 34 }
1 /** 2 * Offloaded version of get() to look up null keys. Null keys map 3 * to index 0. This null case is split out into separate methods 4 * for the sake of performance in the two most commonly used 5 * operations (get and put), but incorporated with conditionals in 6 * others. 7 */ 8 private V getForNullKey() { 9 if (size == 0) { 10 return null; 11 } 12 for (Entry<K,V> e = table[0]; e != null; e = e.next) { 13 if (e.key == null) 14 return e.value; 15 } 16 return null; 17 }
1 /** 2 * Returns index for hash code h.返回hashCode值 3 */ 4 static int indexFor(int h, int length) { 5 // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2"; 6 return h & (length-1); 7 }
解析:首先判断table,也就是数组是否为空,为空的话就去使用inflateTable的方法(这里不多解释)初始化hashmap。
如果table不为空的话,就判断key是否为空,为空的话就将放到数组的index=0的位置,如果value不为空则返回value值。
如果key不为空的话,就通过key获取hash值,通过hash值和table的长度与运算获取hashCode值。
通过hashCode的遍历entry<K,V>的键值对,如果key的hash值相等 并且key.equals(e.key)也相等的话,就将新的value替换掉旧的,返回旧址。