HashMap
可被序列化,线程不安全,允许null值和null键,
安全的Map
Collections.synchronizedMap():
1/** 2 * Returns a synchronized (thread-safe) map backed by the specified map. In order to guarantee 3 * serial access, it is critical that all access to the backing map is accomplished through the 4 * returned map. 5 * It is imperative that the user manually synchronize on the returned map when traversing any of 6 * its collection views via Iterator, Spliterator or Stream: 7 * Map m = Collections.synchronizedMap(new HashMap()); 8 * ... 9 * Set s = m.keySet(); // Needn't be in synchronized block 10 * ... 11 * synchronized (m) { // Synchronizing on m, not s! 12 * Iterator i = s.iterator(); // Must be in synchronized block 13 * while (i.hasNext()) 14 * foo(i.next()); 15 * } 16 */ 17public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) { 18 return new SynchronizedMap<>(m); 19}
ConcurrentHashMap:
默认负载因子为0.75,
static final float DEFAULT_LOAD_FACTOR = 0.75f;
默认初始大小为16,
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
当阈值超过16*0.75=12时,会进行扩增操作,每次扩展会进行2的幂扩展,如果当前容量超过了默认容量大小时,最大容量会变成Integer的最大值
最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;
当容量大于等于64时,HashMap会将列表转化为树(bin的值必须大于2且至少为8)
1/** 2 * The smallest table capacity for which bins may be treeified. 3 * (Otherwise the table is resized if too many nodes in a bin.) 4 * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts 5 * between resizing and treeification thresholds. 6 */ 7static final int MIN_TREEIFY_CAPACITY = 64; 8 9/** 10 * Replaces all linked nodes in bin at index for given hash unless 11 * table is too small, in which case resizes instead. 12 */ 13final void treeifyBin(Node<K,V>[] tab, int hash) { 14 int n, index; Node<K,V> e; 15 if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) 16 resize(); 17 else if ((e = tab[index = (n - 1) & hash]) != null) { 18 TreeNode<K,V> hd = null, tl = null; 19 do { 20 TreeNode<K,V> p = replacementTreeNode(e, null); 21 if (tl == null) 22 hd = p; 23 else { 24 p.prev = tl; 25 tl.next = p; 26 } 27 tl = p; 28 } while ((e = e.next) != null); 29 if ((tab[index] = hd) != null) 30 hd.treeify(tab); 31 } 32 }
在进行put操作时,如果已经有相同的key,则会将其值进行替换。如果hash值相同会进行内存地址比较,如果地址不相同,则会继续进行非空和equals值比较
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 {@code key}, or 9 * {@code null} if there was no mapping for {@code key}. 10 * (A {@code null} return can also indicate that the map 11 * previously associated {@code null} with {@code key}.) 12 */ 13 public V put(K key, V value) { 14 return putVal(hash(key), key, value, false, true); 15 } 16 17 /** 18 * Implements Map.put and related methods. 19 * 20 * @param hash hash for key 21 * @param key the key 22 * @param value the value to put 23 * @param onlyIfAbsent if true, don't change existing value 24 * @param evict if false, the table is in creation mode. 25 * @return previous value, or null if none 26 */ 27 final V putVal(int hash, K key, V value, boolean onlyIfAbsent, 28 boolean evict) { 29 Node<K,V>[] tab; 30 Node<K,V> p; 31 int n, i; 32 if ((tab = table) == null || (n = tab.length) == 0) 33 n = (tab = resize()).length; 34 if ((p = tab[i = (n - 1) & hash]) == null) 35 tab[i] = newNode(hash, key, value, null); 36 else { 37 Node<K,V> e; K k; 38 if (p.hash == hash && 39 ((k = p.key) == key || (key != null && key.equals(k)))) 40 e = p; 41 else if (p instanceof TreeNode) 42 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); 43 else { 44 for (int binCount = 0; ; ++binCount) { 45 if ((e = p.next) == null) { 46 p.next = newNode(hash, key, value, null); 47 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st 48 treeifyBin(tab, hash); 49 break; 50 } 51 if (e.hash == hash && 52 ((k = e.key) == key || (key != null && key.equals(k)))) 53 break; 54 p = e; 55 } 56 } 57 if (e != null) { // existing mapping for key 58 V oldValue = e.value; 59 if (!onlyIfAbsent || oldValue == null) 60 e.value = value; 61 afterNodeAccess(e); 62 return oldValue; 63 } 64 } 65 ++modCount; 66 if (++size > threshold) 67 resize(); 68 afterNodeInsertion(evict); 69 return null; 70 }
