HashMap
<K, V>就是他的泛型,
- K这个Map所包含的键
- V对应映射的类型
概念易错点
- 集合的泛型其实是语法糖,他会在编译器转换成对应的类型
HashMap<> map1 = new HashMap<>();
map1.put("k1", obj1);
HashMap<String, Object> map2 = new HashMap<>();
map2.put("k1", obj1);
解析上是一致的。
两个重要概念
- 没有指明泛型的时候会依照上下文,进行类型推断成对象
- 前面指明泛型,后面会按照JDK1.7自动进行类型推断
G:\Java\WorkSpace_2017Summer>javap -c Something.class
Compiled from "Something.java"
class Something {
java.util.HashMap<java.lang.String, java.lang.Object> map1;
java.util.HashMap map2;
Something();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: new #2 // class java/util/HashMap
8: dup
9: invokespecial #3 // Method java/util/HashMap."<init>":()V
12: putfield #4 // Field map1:Ljava/util/HashMap;
15: aload_0
16: new #2 // class java/util/HashMap
19: dup
20: invokespecial #3 // Method java/util/HashMap."<init>":()V
23: putfield #5 // Field map2:Ljava/util/HashMap;
26: return
void fun();
Code:
0: aload_0
1: getfield #5 // Field map2:Ljava/util/HashMap;
4: ldc #6 // String k1
6: ldc #7 // String v1
8: invokevirtual #8 // Method java/util/HashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
11: pop
12: return
public static void main(java.lang.String[]);
Code:
0: new #9 // class Something
3: dup
4: invokespecial #10 // Method "<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #11 // Method fun:()V
12: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;
15: aload_1
16: getfield #5 // Field map2:Ljava/util/HashMap;
19: ldc #6 // String k1
21: invokevirtual #13 // Method java/util/HashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;
24: invokevirtual #14 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
27: return
}
推断成<Object, Object>
类型了
源码深度分析
ConcurrentMap<>:
A scalable concurrent ConcurrentNavigableMap implementation. The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used.
拓展的并发由ConcurrentNavigableMap实现,map排序按照key的顺序,或者创建时候提供的比较器。
This class implements a concurrent variant of SkipLists providing expected average log(n) time cost for the containsKey, get, put and remove operations and their variants. Insertion, removal, update, and access operations safely execute concurrently by multiple threads.
这个类实现一个了并发变化的SkipLists,为其提供了时间复杂度为log(n)的container,get,put和remove操作。插入,删除,更新和访问操作是多个线程同时安全的执行的。(并发安全的)
HashMap<>:
- 负载因子 The load factor for the hash table.在hash table容量自动增长的时候,测量的对比依据
- 初始化容量 hash表中初始化的数量
迭代器性能取决于负载因子(defaulty load factor = 0.75f)和初始化容量(deafaulty capacity = 1 < 4),如果需要高性能,就不要负载因子太低,或者容量太多 - 顺序 不保证顺序
-
null
允许空值和空键 他会计算得到hash为0,取第一个 -
transient
用transient关键字标记的成员变量不参与序列化过程。 - 线程不安全的访问,我们推荐是
这个我们本质是全部加Map m = Collections.synchronizedMap(new HashMap(...));
sync
锁
Put
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
调用重载总的方法,所有的put都会到这里来
/**
* Implements Map.put and related methods
*
* @param hash hash for key
* @param key the key
* @param value the value to put
* @param onlyIfAbsent if true, don't change existing value 是否覆盖
* @param evict if false, the table is in creation mode. 创建新的节点
* @return previous value, or null if none
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0) // table 是字段属性 Node<K,V>[] table;
n = (tab = resize()).length; // 表为空,就先重新就算长度
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null); // 表中空,就放在Hash表的数组中
else { // 否则放在Hash表的链表中
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k)))) // 表存在Entry
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); //使用LinkHashMap树节点找到
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null); //遍历到末尾,赋值上去
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))// 链表存在
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount; //The number of times this HashMap has been structurally modified
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
Node对象
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next; // 下一个对象
Node(int hash, K key, V value, Node<K,V> next) {/***/}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {/***/}
public final boolean equals(Object o) {/***/}
evict关键字详解主要是用在LinkHashMap中,HashMap未实现
//The head (eldest) of the doubly linked list.
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry<K,V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
HashMap模型
HashMap本质是不安全的,我们推荐使用ConcurrentHashMap
HashSet 对比 HashMap
HashSet本质是使用了HashMap,HashSet = HashMap<E, Object>;