集合
框架关系图:
补充:HashTable父类是Dictionary,不是AbstractMap。
Map:
Map(接口)和Collection都属于集合,但是Map不是Collection的子类或者子接口。而且Map比较特殊:它是以<key,value>键值对的方式来存储数据,其中key不能重复,且一个key最多只对应一个value。
Map在面试中常问的三个子类:HashMap、HashTable、TreeMap。
HashMap:
基于哈希表的实现的Map接口, 该实现提供了所有可选的映射操作,并允许null的key和null的value。
在JDK1.8以前,HashMap底层是:"链表+数组"结构;在JDK1.8时,对HashMap底层进行优化,成了:数组+链表+红黑树。
JDK1.6:初始容量为16,加载因子为0.75,底层是Entry数组加链表结构:
1 //初始容量
2 static final int DEFAULT_INITIAL_CAPACITY = 16;
3 //加载因子
4 static final float DEFAULT_LOAD_FACTOR = 0.75f;
5 //存储容器-数组
6 transient Entry[] table;
7 //静态内部类
8 static class Entry<K,V> implements Map.Entry<K,V> {
9 final K key;
10 V value;
11 Entry<K,V> next;//把key和value转换成数组中的Entry对象
12 final int hash;
13
14 /**
15 * Creates new entry.
16 */
17 Entry(int h, K k, V v, Entry<K,V> n) {
18 value = v;
19 next = n;
20 key = k;
21 hash = h;
22 }
23
24 public final K getKey() {
25 return key;
26 }
27
28 public final V getValue() {
29 return value;
30 }
31
32 public final V setValue(V newValue) {
33 V oldValue = value;
34 value = newValue;
35 return oldValue;
36 }
37
38 public final boolean equals(Object o) {
39 if (!(o instanceof Map.Entry))
40 return false;
41 Map.Entry e = (Map.Entry)o;
42 Object k1 = getKey();
43 Object k2 = e.getKey();
44 if (k1 == k2 || (k1 != null && k1.equals(k2))) {
45 Object v1 = getValue();
46 Object v2 = e.getValue();
47 if (v1 == v2 || (v1 != null && v1.equals(v2)))
48 return true;
49 }
50 return false;
51 }
52
53 public final int hashCode() {
54 return (key==null ? 0 : key.hashCode()) ^
55 (value==null ? 0 : value.hashCode());
56 }
57
58 public final String toString() {
59 return getKey() + "=" + getValue();
60 }
61
62 void recordAccess(HashMap<K,V> m) {
63 }
64
65 void recordRemoval(HashMap<K,V> m) {
66 }
67 }
68 //Put方法
69 public V put(K key, V value) {
70 if (key == null)
71 return putForNullKey(value);//hashmap可以存key==null
72 int hash = hash(key.hashCode());//根据key的hashcode计算一个哈希数
73 int i = indexFor(hash, table.length);//根据计算的哈希数获取数组的坐标
74 for (Entry<K,V> e = table[i]; e != null; e = e.next) {//hashmap不允许重复,如果key重复了,把新的value替换老的value
75 Object k;
76 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//
77 V oldValue = e.value;
78 e.value = value;
79 e.recordAccess(this);
80 return oldValue;
81 }
82 }
83
84 modCount++;
85 addEntry(hash, key, value, i);//处理好以后把hash,key,value,index添加到数组中去
86 return null;
87 }
88 //针对key=null的方法
89 private V putForNullKey(V value) {
90 for (Entry<K,V> e = table[0]; e != null; e = e.next) {
91 if (e.key == null) {
92 V oldValue = e.value;
93 e.value = value;
94 e.recordAccess(this);
95 return oldValue;
96 }
97 }
98 modCount++;
99 addEntry(0, null, value, 0);
100 return null;
101 }
102 //获取哈希数
103 static int hash(int h) {
104 // This function ensures that hashCodes that differ only by
105 // constant multiples at each bit position have a bounded
106 // number of collisions (approximately 8 at default load factor).
107 h ^= (h >>> 20) ^ (h >>> 12);
108 return h ^ (h >>> 7) ^ (h >>> 4);
109 }
110 //获取数组坐标
111 static int indexFor(int h, int length) {
112 return h & (length-1);
113 }
114 //添加元素的方法
115 void addEntry(int hash, K key, V value, int bucketIndex) {
116 Entry<K,V> e = table[bucketIndex];//如果index相同了(哈希碰撞),把原来的值给一个新的Entry对象
117 //然后把新来的值存在数组中,老值作为新值的下标(next对象),在此也体现了hashmap的“链式结构”
118 table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
119 if (size++ >= threshold)
120 resize(2 * table.length);//如果数值超容了,进行扩容:数组的长度*2(默认初始容量16,所以为16*2=32)
121 }
122 //扩容方法
123 void resize(int newCapacity) {//2倍长度作为参数传入
124 Entry[] oldTable = table;
125 int oldCapacity = oldTable.length;
126 if (oldCapacity == MAXIMUM_CAPACITY) {
127 threshold = Integer.MAX_VALUE;
128 return;
129 }
130
131 Entry[] newTable = new Entry[newCapacity];//新建数组
132 transfer(newTable);//数组值转换的方法
133 table = newTable;
134 threshold = (int)(newCapacity * loadFactor);
135 }
136 //数组值转换的方法
137 void transfer(Entry[] newTable) {
138 Entry[] src = table;
139 int newCapacity = newTable.length;
140 for (int j = 0; j < src.length; j++) {
141 Entry<K,V> e = src[j];
142 if (e != null) {
143 src[j] = null;
144 do {//此处为复制的过程
145 Entry<K,V> next = e.next;
146 int i = indexFor(e.hash, newCapacity);
147 e.next = newTable[i];
148 newTable[i] = e;
149 e = next;
150 } while (e != null);
151 }
152 }
153 }
154 //Get方法
155 public V get(Object key) {
156 if (key == null)
157 return getForNullKey();//遍历,获取到key==null的值
158 int hash = hash(key.hashCode());//然后根据key获取哈希值
159 for (Entry<K,V> e = table[indexFor(hash, table.length)];//然后获取坐标得到Entry对象
160 e != null;
161 e = e.next) {//从第一个开始遍历,如果不是,把Entry对象的下标给Entry然后比较
162 Object k;
163 if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
164 return e.value;//当哈希值和key都相等的时候,把value返回去
165 }
166 return null;
167 }
168 //key等于null获取值
169 private V getForNullKey() {
170 for (Entry<K,V> e = table[0]; e != null; e = e.next) {
171 if (e.key == null)
172 return e.value;
173 }
174 return null;
175 }
176 //Clear方法
177 public void clear() {
178 modCount++;
179 Entry[] tab = table;
180 for (int i = 0; i < tab.length; i++)//遍历数组,把值清空,把size置为0
181 tab[i] = null;
182 size = 0;
183 }
184 //entrySet方法:获取到数组中Entry对象的Set集合
185 private transient Set<Map.Entry<K,V>> entrySet = null;
186
187 public Set<Map.Entry<K,V>> entrySet() {
188 return entrySet0();
189 }
190 private Set<Map.Entry<K,V>> entrySet0() {
191 Set<Map.Entry<K,V>> es = entrySet;
192 return es != null ? es : (entrySet = new EntrySet());
193 }
194 //原理就是迭代map中的Entry对象
195 private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
196 public Iterator<Map.Entry<K,V>> iterator() {
197 return newEntryIterator();
198 }
199 public boolean contains(Object o) {
200 if (!(o instanceof Map.Entry))
201 return false;
202 Map.Entry<K,V> e = (Map.Entry<K,V>) o;
203 Entry<K,V> candidate = getEntry(e.getKey());
204 return candidate != null && candidate.equals(e);
205 }
206 public boolean remove(Object o) {
207 return removeMapping(o) != null;
208 }
209 public int size() {
210 return size;
211 }
212 public void clear() {
213 HashMap.this.clear();
214 }
215 }
216 final Entry<K,V> nextEntry() {
217 if (modCount != expectedModCount)
218 throw new ConcurrentModificationException();
219 Entry<K,V> e = next;
220 if (e == null)
221 throw new NoSuchElementException();
222
223 if ((next = e.next) == null) {
224 Entry[] t = table;
225 while (index < t.length && (next = t[index++]) == null) ;
226 }
227 current = e;
228 return e;
229 }
230 //keySet方法
231 public Set<K> keySet() {
232 Set<K> ks = keySet;
233 return (ks != null ? ks : (keySet = new KeySet()));
234 }
235 //原理也是通过迭代器,迭代Entry对象,然后获取key
236 private final class KeySet extends AbstractSet<K> {
237 public Iterator<K> iterator() {
238 return newKeyIterator();
239 }
240 public int size() {
241 return size;
242 }
243 public boolean contains(Object o) {
244 return containsKey(o);
245 }
246 public boolean remove(Object o) {
247 return HashMap.this.removeEntryForKey(o) != null;
248 }
249 public void clear() {
250 HashMap.this.clear();
251 }
252 }
253
254 private final class KeyIterator extends HashIterator<K> {
255 public K next() {
256 return nextEntry().getKey();
257 }
258 }
259 //remove方法
260 public V remove(Object key) {
261 Entry<K,V> e = removeEntryForKey(key);
262 return (e == null ? null : e.value);
263 }
264 final Entry<K,V> removeEntryForKey(Object key) {
265 int hash = (key == null) ? 0 : hash(key.hashCode());
266 int i = indexFor(hash, table.length);
267 Entry<K,V> prev = table[i];
268 Entry<K,V> e = prev;
269
270 while (e != null) {//用while循环,当哈希值和key都相等的时候把值得next赋值给现在位置的值
271 Entry<K,V> next = e.next;
272 Object k;
273 if (e.hash == hash &&
274 ((k = e.key) == key || (key != null && key.equals(k)))) {
275 modCount++;
276 size--;
277 if (prev == e)
278 table[i] = next;
279 else
280 prev.next = next;
281 e.recordRemoval(this);
282 return e;
283 }
284 prev = e;
285 e = next;
286 }
287
288 return e;
289 }
290 //size方法和isEmpty方法
291 transient int size;//和put以及remove方法有关系,增加就++,删除就--
292 public int size() {
293 return size;
294 }
295 public boolean isEmpty() {
296 return size == 0;
297 }
298 //contains方法
299 public boolean contains(Object o) {
300 return containsKey(o);
301 }
302 public boolean containsKey(Object key) {
303 return getEntry(key) != null;
304 }
305 final Entry<K,V> getEntry(Object key) {
306 if (size == 0) {
307 return null;
308 }
309
310 int hash = (key == null) ? 0 : hash(key);
311 for (Entry<K,V> e = table[indexFor(hash, table.length)];
312 e != null;
313 e = e.next) {
314 Object k;
315 if (e.hash == hash &&
316 ((k = e.key) == key || (key != null && key.equals(k))))
317 return e;
318 }
319 return null;
320 }
补充1:
哈希表(Hash table,采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表(Hash table)),是根据关键码值(Key value)而直接进行访问的数据结构,也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。
记录的存储位置=f(关键字),被称为散列函数,又称为哈希(Hash函数),
补充二:
两个对象相等,hashCode一定相同,但是两个对象的HashCode相同,这两个对象不一定相等。
JDK1.7源码(和1.6的对比):
1 //对比一:1.7默认初始容量用了位移计算
2 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
3 //加载因子
4 static final float DEFAULT_LOAD_FACTOR = 0.75f;
5 //存储容器-数组
6 static final Entry<?,?>[] EMPTY_TABLE = {};
7
8 transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
9 //静态内部类
10 static class Entry<K,V> implements Map.Entry<K,V> {
11 final K key;
12 V value;
13 Entry<K,V> next;
14 int hash;
15
16 /**
17 * Creates new entry.
18 */
19 Entry(int h, K k, V v, Entry<K,V> n) {
20 value = v;
21 next = n;
22 key = k;
23 hash = h;
24 }
25
26 public final K getKey() {
27 return key;
28 }
29
30 public final V getValue() {
31 return value;
32 }
33
34 public final V setValue(V newValue) {
35 V oldValue = value;
36 value = newValue;
37 return oldValue;
38 }
39
40 public final boolean equals(Object o) {
41 if (!(o instanceof Map.Entry))
42 return false;
43 Map.Entry e = (Map.Entry)o;
44 Object k1 = getKey();
45 Object k2 = e.getKey();
46 if (k1 == k2 || (k1 != null && k1.equals(k2))) {
47 Object v1 = getValue();
48 Object v2 = e.getValue();
49 if (v1 == v2 || (v1 != null && v1.equals(v2)))
50 return true;
51 }
52 return false;
53 }
54
55 public final int hashCode() {
56 return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
57 }
58
59 public final String toString() {
60 return getKey() + "=" + getValue();
61 }
62
63 /**
64 * This method is invoked whenever the value in an entry is
65 * overwritten by an invocation of put(k,v) for a key k that's already
66 * in the HashMap.
67 */
68 void recordAccess(HashMap<K,V> m) {
69 }
70
71 /**
72 * This method is invoked whenever the entry is
73 * removed from the table.
74 */
75 void recordRemoval(HashMap<K,V> m) {
76 }
77 }
78 //Put方法
79 public V put(K key, V value) {
80 if (table == EMPTY_TABLE) {//此出多了一个数组初始化的方法
81 inflateTable(threshold);
82 }
83 if (key == null)
84 return putForNullKey(value);
85 int hash = hash(key);
86 int i = indexFor(hash, table.length);
87 for (Entry<K,V> e = table[i]; e != null; e = e.next) {
88 Object k;
89 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
90 V oldValue = e.value;
91 e.value = value;
92 e.recordAccess(this);
93 return oldValue;
94 }
95 }
96
97 modCount++;
98 addEntry(hash, key, value, i);
99 return null;
100 }
101 //初始化数组
102 private void inflateTable(int toSize) {
103
104 int capacity = roundUpToPowerOf2(toSize); // 此处把传入的数组容量向上转换为2的n次幂的数值
105
106 threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
107 table = new Entry[capacity];
108 initHashSeedAsNeeded(capacity);
109 }
110 final boolean initHashSeedAsNeeded(int capacity) {
111 boolean currentAltHashing = hashSeed != 0;
112 boolean useAltHashing = sun.misc.VM.isBooted() &&
113 (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
114 boolean switching = currentAltHashing ^ useAltHashing;
115 if (switching) {
116 hashSeed = useAltHashing
117 ? sun.misc.Hashing.randomHashSeed(this)
118 : 0;
119 }
120 return switching;
121 }
122 //针对key=null的方法
123 private V putForNullKey(V value) {
124 for (Entry<K,V> e = table[0]; e != null; e = e.next) {
125 if (e.key == null) {
126 V oldValue = e.value;
127 e.value = value;
128 e.recordAccess(this);
129 return oldValue;
130 }
131 }
132 modCount++;
133 addEntry(0, null, value, 0);
134 return null;
135 }
136 //获取哈希数
137 final int hash(Object k) {
138 int h = hashSeed;
139 if (0 != h && k instanceof String) {
140 return sun.misc.Hashing.stringHash32((String) k);
141 }
142
143 h ^= k.hashCode();
144
145 h ^= (h >>> 20) ^ (h >>> 12);
146 return h ^ (h >>> 7) ^ (h >>> 4);
147 }
148 //获取数组坐标
149 static int indexFor(int h, int length) {
150 // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
151 return h & (length-1);
152 }
153 //添加元素的方法
154 void addEntry(int hash, K key, V value, int bucketIndex) {
155 if ((size >= threshold) && (null != table[bucketIndex])) {//1.7这里先进行是否需要扩容的判断
156 resize(2 * table.length);
157 hash = (null != key) ? hash(key) : 0;
158 bucketIndex = indexFor(hash, table.length);
159 }
160
161 createEntry(hash, key, value, bucketIndex);
162 }
163 //扩容方法
164 void resize(int newCapacity) {
165 Entry[] oldTable = table;
166 int oldCapacity = oldTable.length;
167 if (oldCapacity == MAXIMUM_CAPACITY) {
168 threshold = Integer.MAX_VALUE;
169 return;
170 }
171
172 Entry[] newTable = new Entry[newCapacity];
173 transfer(newTable, initHashSeedAsNeeded(newCapacity));
174 table = newTable;
175 threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
176 }
177 //数组值转换的方法
178 void transfer(Entry[] newTable, boolean rehash) {
179 int newCapacity = newTable.length;
180 for (Entry<K,V> e : table) {
181 while(null != e) {
182 Entry<K,V> next = e.next;
183 if (rehash) {
184 e.hash = null == e.key ? 0 : hash(e.key);
185 }
186 int i = indexFor(e.hash, newCapacity);
187 e.next = newTable[i];
188 newTable[i] = e;
189 e = next;
190 }
191 }
192 }
193 //添加元素的方法
194 void createEntry(int hash, K key, V value, int bucketIndex) {
195 Entry<K,V> e = table[bucketIndex];
196 table[bucketIndex] = new Entry<>(hash, key, value, e);
197 size++;
198 }
199 //Get方法
200 public V get(Object key) {
201 if (key == null)
202 return getForNullKey();
203 Entry<K,V> entry = getEntry(key);
204
205 return null == entry ? null : entry.getValue();
206 }
207 //key等于null获取值
208 private V getForNullKey() {
209 if (size == 0) {//1.7在此处又多了个判断数组是否为空的情况
210 return null;
211 }
212 for (Entry<K,V> e = table[0]; e != null; e = e.next) {
213 if (e.key == null)
214 return e.value;
215 }
216 return null;
217 }
218 //Clear方法
219 public void clear() {
220 modCount++;
221 Arrays.fill(table, null);//1,7此处调用了Arrays中的方法,不过原理还是一样的
222 size = 0;
223 }
224
225 public static void fill(Object[] a, Object val) {
226 for (int i = 0, len = a.length; i < len; i++)
227 a[i] = val;
228 }
229 //entrySet方法:获取到数组中Entry对象的Set集合
230 private transient Set<Map.Entry<K,V>> entrySet = null;
231
232 public Set<Map.Entry<K,V>> entrySet() {
233 return entrySet0();
234 }
235
236 private Set<Map.Entry<K,V>> entrySet0() {
237 Set<Map.Entry<K,V>> es = entrySet;
238 return es != null ? es : (entrySet = new EntrySet());
239 }
240 //原理就是迭代map中的Entry对象
241 private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
242 public Iterator<Map.Entry<K,V>> iterator() {
243 return newEntryIterator();
244 }
245 public boolean contains(Object o) {
246 if (!(o instanceof Map.Entry))
247 return false;
248 Map.Entry<K,V> e = (Map.Entry<K,V>) o;
249 Entry<K,V> candidate = getEntry(e.getKey());
250 return candidate != null && candidate.equals(e);
251 }
252 public boolean remove(Object o) {
253 return removeMapping(o) != null;
254 }
255 public int size() {
256 return size;
257 }
258 public void clear() {
259 HashMap.this.clear();
260 }
261 }
262 //keySet方法
263 public Set<K> keySet() {
264 Set<K> ks = keySet;
265 return (ks != null ? ks : (keySet = new KeySet()));
266 }
267 //原理也是通过迭代器,迭代Entry对象,然后获取key
268 private final class KeySet extends AbstractSet<K> {
269 public Iterator<K> iterator() {
270 return newKeyIterator();
271 }
272 public int size() {
273 return size;
274 }
275 public boolean contains(Object o) {
276 return containsKey(o);
277 }
278 public boolean remove(Object o) {
279 return HashMap.this.removeEntryForKey(o) != null;
280 }
281 public void clear() {
282 HashMap.this.clear();
283 }
284 }
285 //remove方法
286 public V remove(Object key) {
287 Entry<K,V> e = removeEntryForKey(key);
288 return (e == null ? null : e.value);
289 }
290
291 final Entry<K,V> removeEntryForKey(Object key) {
292 if (size == 0) {
293 return null;
294 }
295 int hash = (key == null) ? 0 : hash(key);
296 int i = indexFor(hash, table.length);
297 Entry<K,V> prev = table[i];
298 Entry<K,V> e = prev;
299
300 while (e != null) {
301 Entry<K,V> next = e.next;
302 Object k;
303 if (e.hash == hash &&
304 ((k = e.key) == key || (key != null && key.equals(k)))) {
305 modCount++;
306 size--;
307 if (prev == e)
308 table[i] = next;
309 else
310 prev.next = next;
311 e.recordRemoval(this);
312 return e;
313 }
314 prev = e;
315 e = next;
316 }
317
318 return e;
319 }
320 //size方法、isEmpty方法、contains方法
321 public int size() {
322 return size;
323 }
324 public boolean isEmpty() {
325 return size == 0;
326 }
327
328 public boolean contains(Object o) {
329 return containsKey(o);
330 }
331 public boolean containsKey(Object key) {
332 return getEntry(key) != null;
333 }
334 final Entry<K,V> getEntry(Object key) {
335 if (size == 0) {
336 return null;
337 }
338
339 int hash = (key == null) ? 0 : hash(key);
340 for (Entry<K,V> e = table[indexFor(hash, table.length)];
341 e != null;
342 e = e.next) {
343 Object k;
344 if (e.hash == hash &&
345 ((k = e.key) == key || (key != null && key.equals(k))))
346 return e;
347 }
348 return null;
349 }
对比可以看出,1.6和1.7重要方法的原理基本没变,1.7在部分方法上做了一点小的优化,还有就是从1.7开始,创建无参hashmap时不直接生成数组了,采用懒加载的方式,在用的时候再初始化。
1.6无参构造函数:
1 public HashMap() {
2 this.loadFactor = DEFAULT_LOAD_FACTOR;
3 threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
4 table = new Entry[DEFAULT_INITIAL_CAPACITY];
5 init();
6 }
1.7无参构造函数(在Put方法中,判断table等于空的时候再创建):
1 public HashMap() {
2 this.loadFactor = DEFAULT_LOAD_FACTOR;
3 }
HashMap1.8:初始容量为16,加载因子为0.75,底层是Node数组+链表+红黑树:
1 //初始容量
2 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
3 //加载因子
4 static final float DEFAULT_LOAD_FACTOR = 0.75f;
5 //转为红黑树的阈(yu)值
6 static final int TREEIFY_THRESHOLD = 8;
7 //从红黑树转换为链表的阈值(扩容会重新计算一次数据长度)
8 static final int UNTREEIFY_THRESHOLD = 6;
9 //默认红黑树的容量
10 static final int MIN_TREEIFY_CAPACITY = 64;
11 //存储容器-数组,由1.7的Entry<K,V>[]数组变为了Node<K,V>[]
12
13 transient Node<K,V>[] table;
14
15 static class Node<K,V> implements Map.Entry<K,V> {
16 final int hash;
17 final K key;
18 V value;
19 Node<K,V> next;
20
21 Node(int hash, K key, V value, Node<K,V> next) {
22 this.hash = hash;
23 this.key = key;
24 this.value = value;
25 this.next = next;
26 }
27
28 public final K getKey() { return key; }
29 public final V getValue() { return value; }
30 public final String toString() { return key + "=" + value; }
31
32 public final int hashCode() {
33 return Objects.hashCode(key) ^ Objects.hashCode(value);
34 }
35
36 public final V setValue(V newValue) {
37 V oldValue = value;
38 value = newValue;
39 return oldValue;
40 }
41
42 public final boolean equals(Object o) {
43 if (o == this)
44 return true;
45 if (o instanceof Map.Entry) {
46 Map.Entry<?,?> e = (Map.Entry<?,?>)o;
47 if (Objects.equals(key, e.getKey()) &&
48 Objects.equals(value, e.getValue()))
49 return true;
50 }
51 return false;
52 }
53 }
54 //Put方法
55 public V put(K key, V value) {
56 return putVal(hash(key), key, value, false, true);
57 }
58
59 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
60 boolean evict) {
61 Node<K,V>[] tab; Node<K,V> p; int n, i;
62 if ((tab = table) == null || (n = tab.length) == 0)
63 n = (tab = resize()).length;//首先还是先判断数组是否为空的,是的话进行初始化
64 if ((p = tab[i = (n - 1) & hash]) == null)//如果数组该位置为空,则把key,value传入该位置
65 tab[i] = newNode(hash, key, value, null);
66 else {//走到这说明发生了哈希碰撞,计算的key的哈希值相同
67 Node<K,V> e; K k;
68 if (p.hash == hash &&
69 ((k = p.key) == key || (key != null && key.equals(k))))//先比较数据是否重复,重复的话就新值替换旧值
70 e = p;
71 else if (p instanceof TreeNode)//判断该对象是不是红黑树的元素,是的话直接存入红黑树
72 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
73 else {
74 for (int binCount = 0; ; ++binCount) {//遍历链表上的元素
75 if ((e = p.next) == null) {
76 p.next = newNode(hash, key, value, null);
77 if (binCount >= TREEIFY_THRESHOLD - 1) // 如果数量达到临界点,则转换为红黑树
78 treeifyBin(tab, hash);//转换方法
79 break;
80 }
81 if (e.hash == hash &&
82 ((k = e.key) == key || (key != null && key.equals(k))))
83 break;
84 p = e;//e其实是p.next,此处体现1.8的尾插法
85 }
86 }
87 if (e != null) { // 此处作用为,当key相同时,新value替换老的value,并将oleValue返回出去
88 V oldValue = e.value;
89 if (!onlyIfAbsent || oldValue == null)
90 e.value = value;
91 afterNodeAccess(e);
92 return oldValue;
93 }
94 }
95 ++modCount;
96 if (++size > threshold)//如果数组大于初始量*加载因子,则进行扩容
97 resize();
98 afterNodeInsertion(evict);
99 return null;
100 }
101 //空数组初始化方法
102 final Node<K,V>[] resize() {
103 Node<K,V>[] oldTab = table;
104 int oldCap = (oldTab == null) ? 0 : oldTab.length;
105 int oldThr = threshold;
106 int newCap, newThr = 0;
107 if (oldCap > 0) {
108 if (oldCap >= MAXIMUM_CAPACITY) {
109 threshold = Integer.MAX_VALUE;
110 return oldTab;
111 }
112 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
113 oldCap >= DEFAULT_INITIAL_CAPACITY)
114 newThr = oldThr << 1; // double threshold
115 }
116 else if (oldThr > 0) // initial capacity was placed in threshold
117 newCap = oldThr;
118 else { // zero initial threshold signifies using defaults
119 newCap = DEFAULT_INITIAL_CAPACITY;
120 newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
121 }
122 if (newThr == 0) {
123 float ft = (float)newCap * loadFactor;
124 newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
125 (int)ft : Integer.MAX_VALUE);
126 }
127 threshold = newThr;
128 @SuppressWarnings({"rawtypes","unchecked"})
129 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
130 table = newTab;
131 if (oldTab != null) {
132 for (int j = 0; j < oldCap; ++j) {
133 Node<K,V> e;
134 if ((e = oldTab[j]) != null) {
135 oldTab[j] = null;
136 if (e.next == null)
137 newTab[e.hash & (newCap - 1)] = e;
138 else if (e instanceof TreeNode)
139 ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
140 else { // preserve order
141 Node<K,V> loHead = null, loTail = null;
142 Node<K,V> hiHead = null, hiTail = null;
143 Node<K,V> next;
144 do {
145 next = e.next;
146 if ((e.hash & oldCap) == 0) {
147 if (loTail == null)
148 loHead = e;
149 else
150 loTail.next = e;
151 loTail = e;
152 }
153 else {
154 if (hiTail == null)
155 hiHead = e;
156 else
157 hiTail.next = e;
158 hiTail = e;
159 }
160 } while ((e = next) != null);
161 if (loTail != null) {
162 loTail.next = null;
163 newTab[j] = loHead;
164 }
165 if (hiTail != null) {
166 hiTail.next = null;
167 newTab[j + oldCap] = hiHead;
168 }
169 }
170 }
171 }
172 }
173 return newTab;
174 }
175 //存入红黑树
176 final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
177 int h, K k, V v) {
178 Class<?> kc = null;
179 boolean searched = false;
180 TreeNode<K,V> root = (parent != null) ? root() : this;
181 for (TreeNode<K,V> p = root;;) {
182 int dir, ph; K pk;
183 if ((ph = p.hash) > h)
184 dir = -1;
185 else if (ph < h)
186 dir = 1;
187 else if ((pk = p.key) == k || (k != null && k.equals(pk)))
188 return p;
189 else if ((kc == null &&
190 (kc = comparableClassFor(k)) == null) ||
191 (dir = compareComparables(kc, k, pk)) == 0) {
192 if (!searched) {
193 TreeNode<K,V> q, ch;
194 searched = true;
195 if (((ch = p.left) != null &&
196 (q = ch.find(h, k, kc)) != null) ||
197 ((ch = p.right) != null &&
198 (q = ch.find(h, k, kc)) != null))
199 return q;
200 }
201 dir = tieBreakOrder(k, pk);
202 }
203
204 TreeNode<K,V> xp = p;
205 if ((p = (dir <= 0) ? p.left : p.right) == null) {
206 Node<K,V> xpn = xp.next;
207 TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
208 if (dir <= 0)
209 xp.left = x;
210 else
211 xp.right = x;
212 xp.next = x;
213 x.parent = x.prev = xp;
214 if (xpn != null)
215 ((TreeNode<K,V>)xpn).prev = x;
216 moveRootToFront(tab, balanceInsertion(root, x));
217 return null;
218 }
219 }
220 }
221 //转换为红黑树
222 final void treeifyBin(Node<K,V>[] tab, int hash) {
223 int n, index; Node<K,V> e;
224 if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
225 resize();
226 else if ((e = tab[index = (n - 1) & hash]) != null) {
227 TreeNode<K,V> hd = null, tl = null;
228 do {
229 TreeNode<K,V> p = replacementTreeNode(e, null);
230 if (tl == null)
231 hd = p;
232 else {
233 p.prev = tl;
234 tl.next = p;
235 }
236 tl = p;
237 } while ((e = e.next) != null);
238 if ((tab[index] = hd) != null)
239 hd.treeify(tab);
240 }
241 }
242 //扩容方法
243 final Node<K,V>[] resize() {
244 Node<K,V>[] oldTab = table;
245 int oldCap = (oldTab == null) ? 0 : oldTab.length;
246 int oldThr = threshold;
247 int newCap, newThr = 0;
248 if (oldCap > 0) {
249 if (oldCap >= MAXIMUM_CAPACITY) {
250 threshold = Integer.MAX_VALUE;
251 return oldTab;
252 }
253 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
254 oldCap >= DEFAULT_INITIAL_CAPACITY)
255 newThr = oldThr << 1; // double threshold
256 }
257 else if (oldThr > 0) // initial capacity was placed in threshold
258 newCap = oldThr;
259 else { // zero initial threshold signifies using defaults
260 newCap = DEFAULT_INITIAL_CAPACITY;
261 newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
262 }
263 if (newThr == 0) {
264 float ft = (float)newCap * loadFactor;
265 newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
266 (int)ft : Integer.MAX_VALUE);
267 }
268 threshold = newThr;
269 @SuppressWarnings({"rawtypes","unchecked"})
270 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
271 table = newTab;
272 if (oldTab != null) {
273 for (int j = 0; j < oldCap; ++j) {
274 Node<K,V> e;
275 if ((e = oldTab[j]) != null) {
276 oldTab[j] = null;
277 if (e.next == null)
278 newTab[e.hash & (newCap - 1)] = e;
279 else if (e instanceof TreeNode)
280 ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
281 else { // preserve order
282 Node<K,V> loHead = null, loTail = null;
283 Node<K,V> hiHead = null, hiTail = null;
284 Node<K,V> next;
285 do {
286 next = e.next;
287 if ((e.hash & oldCap) == 0) {
288 if (loTail == null)
289 loHead = e;
290 else
291 loTail.next = e;
292 loTail = e;
293 }
294 else {
295 if (hiTail == null)
296 hiHead = e;
297 else
298 hiTail.next = e;
299 hiTail = e;
300 }
301 } while ((e = next) != null);
302 if (loTail != null) {
303 loTail.next = null;
304 newTab[j] = loHead;
305 }
306 if (hiTail != null) {
307 hiTail.next = null;
308 newTab[j + oldCap] = hiHead;
309 }
310 }
311 }
312 }
313 }
314 return newTab;
315 }
316 //Get方法,加入很多的判断,以保证数据的准确性
317 public V get(Object key) {
318 Node<K,V> e;
319 return (e = getNode(hash(key), key)) == null ? null : e.value;
320 }
321
322 final Node<K,V> getNode(int hash, Object key) {
323 Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
324 if ((tab = table) != null && (n = tab.length) > 0 &&
325 (first = tab[(n - 1) & hash]) != null) {
326 if (first.hash == hash && // always check first node
327 ((k = first.key) == key || (key != null && key.equals(k))))
328 return first;
329 if ((e = first.next) != null) {
330 if (first instanceof TreeNode)
331 return ((TreeNode<K,V>)first).getTreeNode(hash, key);//如果是红黑树,则用红黑树的get方法
332 do {
333 if (e.hash == hash &&
334 ((k = e.key) == key || (key != null && key.equals(k))))
335 return e;
336 } while ((e = e.next) != null);
337 }
338 }
339 return null;
340 }
341 //1.8取消了contans方法,用containsKey和ContainsValue
342 public boolean containsKey(Object key) {
343 return getNode(hash(key), key) != null;
344 }
345
346 public boolean containsValue(Object value) {
347 Node<K,V>[] tab; V v;
348 if ((tab = table) != null && size > 0) {
349 for (int i = 0; i < tab.length; ++i) {
350 for (Node<K,V> e = tab[i]; e != null; e = e.next) {
351 if ((v = e.value) == value ||
352 (value != null && value.equals(v)))
353 return true;
354 }
355 }
356 }
357 return false;
358 }
359 //entrySet方法
360 public Set<Map.Entry<K,V>> entrySet() {
361 Set<Map.Entry<K,V>> es;
362 return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
363 }
364
365 final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
366 public final int size() { return size; }
367 public final void clear() { HashMap.this.clear(); }
368 public final Iterator<Map.Entry<K,V>> iterator() {
369 return new EntryIterator();
370 }
371 public final boolean contains(Object o) {
372 if (!(o instanceof Map.Entry))
373 return false;
374 Map.Entry<?,?> e = (Map.Entry<?,?>) o;
375 Object key = e.getKey();
376 Node<K,V> candidate = getNode(hash(key), key);
377 return candidate != null && candidate.equals(e);
378 }
379 public final boolean remove(Object o) {
380 if (o instanceof Map.Entry) {
381 Map.Entry<?,?> e = (Map.Entry<?,?>) o;
382 Object key = e.getKey();
383 Object value = e.getValue();
384 return removeNode(hash(key), key, value, true, true) != null;
385 }
386 return false;
387 }
388 public final Spliterator<Map.Entry<K,V>> spliterator() {
389 return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
390 }
391 public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
392 Node<K,V>[] tab;
393 if (action == null)
394 throw new NullPointerException();
395 if (size > 0 && (tab = table) != null) {
396 int mc = modCount;
397 for (int i = 0; i < tab.length; ++i) {
398 for (Node<K,V> e = tab[i]; e != null; e = e.next)
399 action.accept(e);
400 }
401 if (modCount != mc)
402 throw new ConcurrentModificationException();
403 }
404 }
405 }
406 //keySet
407 public Set<K> keySet() {
408 Set<K> ks;
409 return (ks = keySet) == null ? (keySet = new KeySet()) : ks;
410 }
411
412 final class KeySet extends AbstractSet<K> {
413 public final int size() { return size; }
414 public final void clear() { HashMap.this.clear(); }
415 public final Iterator<K> iterator() { return new KeyIterator(); }
416 public final boolean contains(Object o) { return containsKey(o); }
417 public final boolean remove(Object key) {
418 return removeNode(hash(key), key, null, false, true) != null;
419 }
420 public final Spliterator<K> spliterator() {
421 return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
422 }
423 public final void forEach(Consumer<? super K> action) {
424 Node<K,V>[] tab;
425 if (action == null)
426 throw new NullPointerException();
427 if (size > 0 && (tab = table) != null) {
428 int mc = modCount;
429 for (int i = 0; i < tab.length; ++i) {
430 for (Node<K,V> e = tab[i]; e != null; e = e.next)
431 action.accept(e.key);
432 }
433 if (modCount != mc)
434 throw new ConcurrentModificationException();
435 }
436 }
437 }
438 //remove方法
439 public boolean remove(Object key, Object value) {
440 return removeNode(hash(key), key, value, true, true) != null;
441 }
442
443 final Node<K,V> removeNode(int hash, Object key, Object value,
444 boolean matchValue, boolean movable) {
445 Node<K,V>[] tab; Node<K,V> p; int n, index;
446 if ((tab = table) != null && (n = tab.length) > 0 &&
447 (p = tab[index = (n - 1) & hash]) != null) {
448 Node<K,V> node = null, e; K k; V v;
449 if (p.hash == hash &&
450 ((k = p.key) == key || (key != null && key.equals(k))))
451 node = p;
452 else if ((e = p.next) != null) {
453 if (p instanceof TreeNode)
454 node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
455 else {
456 do {
457 if (e.hash == hash &&
458 ((k = e.key) == key ||
459 (key != null && key.equals(k)))) {
460 node = e;
461 break;
462 }
463 p = e;
464 } while ((e = e.next) != null);
465 }
466 }
467 if (node != null && (!matchValue || (v = node.value) == value ||
468 (value != null && value.equals(v)))) {
469 if (node instanceof TreeNode)
470 ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
471 else if (node == p)
472 tab[index] = node.next;
473 else
474 p.next = node.next;
475 ++modCount;
476 --size;
477 afterNodeRemoval(node);
478 return node;
479 }
480 }
481 return null;
482 }
483 //size方法和isEmpty方法
484 transient int size;//和put以及remove方法有关系,增加就++,删除就--
485
486 public int size() {
487 return size;
488 }
489
490 public boolean isEmpty() {
491 return size == 0;
492 }
对比一下可以发现,在JDK1.8的时候,hashmap有了很大的改变,不止加了很多小的优化,而且还添加红黑树用来解决哈希碰撞导致的的查询问题。
为什么要转换为红黑树?
红黑树具有很高效的查找功能,当数值不多时用链表的形式就可以应对问题,但是当链表很长的时候(发生了哈希碰撞多),hashmap在进行put和get等方法时都需要遍历链表,红黑树可以保证hashmap在发生哈希碰撞时能保证数据元素的高效定位。
为什么转为红黑树的阈(yu)值为8?
因为由链表转换成红黑树时,需要额外的空间和时间,根据“泊松分布”算出,出现链表长度为8的情况已经非常小了,大概是:0.00000006,所以在8的时候再转换为红黑树。