3.1HashMap源码分析
在前篇博文中(HashMap原理及实现学习总结)详细总结了HashMap的原理及实现过程,这一篇是对HashMap的源码分析。
1 package dataStructure.hash; 2 3 import java.io.*; 4 import java.util.AbstractCollection; 5 import java.util.AbstractMap; 6 import java.util.AbstractSet; 7 import java.util.Collection; 8 import java.util.ConcurrentModificationException; 9 import java.util.Iterator; 10 import java.util.Map; 11 import java.util.NoSuchElementException; 12 import java.util.Set; 13 14 public class HashMap<K, V> extends AbstractMap<K, V>implements Map<K, V>, Cloneable, Serializable { 15 16 // 系统默认初始容量,必须是2的n次幂,这是出于优化考虑的 17 static final int DEFAULT_INITIAL_CAPACITY = 16; 18 19 // 系统默认最大容量 20 static final int MAXIMUM_CAPACITY = 1 << 30; 21 22 // 系统默认负载因子,可在构造函数中指定 23 static final float DEFAULT_LOAD_FACTOR = 0.75f; 24 25 // 用于存储的表,长度可以调整,且必须是2的n次幂 26 transient Entry[] table; 27 28 // 当前map的key-value映射数,也就是当前size 29 transient int size; 30 31 // 阈值 32 int threshold; 33 34 // 哈希表的负载因子 35 final float loadFactor; 36 37 // 用于确保使用迭代器的时候,HashMap并未进行更改 38 transient volatile int modCount; 39 40 // 构造一个带指定初始容量和加载因子的空 HashMap。 41 public HashMap(int initialCapacity, float loadFactor) { 42 // 如果指定初始容量小于0,抛错 43 if (initialCapacity < 0) 44 throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); 45 // 如果初始容量大于系统默认最大容量,则初始容量为最大容量 46 if (initialCapacity > MAXIMUM_CAPACITY) 47 initialCapacity = MAXIMUM_CAPACITY; 48 // 如果loadFactor小于0,或loadFactor是NaN,则抛错 49 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 50 throw new IllegalArgumentException("Illegal load factor: " + loadFactor); 51 52 // 寻找一个2的k次幂capacity恰好大于initialCapacity 53 int capacity = 1; 54 while (capacity < initialCapacity) 55 capacity <<= 1; 56 57 // 设置加载因子 58 this.loadFactor = loadFactor; 59 // 设置阈值为capacity * loadFactor,实际上当HashMap当前size到达这个阈值时,HashMap就需要扩大一倍了。 60 threshold = (int) (capacity * loadFactor); 61 // 创建一个capacity长度的数组用于保存数据 62 table = new Entry[capacity]; 63 // 开始初始化 64 init(); 65 } 66 67 // 构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap。 68 public HashMap(int initialCapacity) { 69 this(initialCapacity, DEFAULT_LOAD_FACTOR); 70 } 71 72 // 构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。 73 public HashMap() { 74 this.loadFactor = DEFAULT_LOAD_FACTOR; 75 threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); 76 table = new Entry[DEFAULT_INITIAL_CAPACITY]; 77 init(); 78 } 79 80 // 构造一个映射关系与指定 Map 相同的新 HashMap。 81 public HashMap(Map<? extends K, ? extends V> m) { 82 this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); 83 putAllForCreate(m); 84 } 85 86 // 内部公用工具 87 88 // 定义一个空方法用于未来的子对象扩展,该方法用于初始化之后,插入元素之前 89 void init() { 90 } 91 92 // 预处理hash值,避免较差的离散hash序列,导致桶没有充分利用 93 static int hash(int h) { 94 h ^= (h >>> 20) ^ (h >>> 12); 95 return h ^ (h >>> 7) ^ (h >>> 4); 96 } 97 98 // 返回对应hash值得索引 99 static int indexFor(int h, int length) { 100 /***************** 101 * 由于length是2的n次幂,所以h & (length-1)相当于h % length。 102 * 对于length,其2进制表示为1000...0,那么length-1为0111...1。 103 * 那么对于任何小于length的数h,该式结果都是其本身h。 对于h = length,该式结果等于0。 104 * 对于大于length的数h,则和0111...1位与运算后, 比0111...1高或者长度相同的位都变成0, 105 * 相当于减去j个length,该式结果是h-j*length, 所以相当于h % length。 其中一个很常用的特例就是h & 1相当于h 106 * % 2。 这也是为什么length只能是2的n次幂的原因,为了优化。 107 */ 108 return h & (length - 1); 109 } 110 111 // 返回当前map的key-value映射数,也就是当前size 112 public int size() { 113 return size; 114 } 115 116 // 该HashMap是否是空的,如果size为0,则为空 117 public boolean isEmpty() { 118 return size == 0; 119 } 120 121 // 返回指定键所映射的值;如果对于该键来说,此映射不包含任何映射关系,则返回 null 122 public V get(Object key) { 123 // 若为null,调用getForNullKey方法返回相对应的value 124 if (key == null) 125 return getForNullKey(); 126 // 根据该 key 的 hashCode 值计算它的 hash 码 127 int hash = hash(key.hashCode()); 128 // 取出 table 数组中指定索引处的值 129 for (Entry<K, V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { 130 Object k; 131 // 如果hash值相等,并且key相等则证明这个桶里的东西是我们想要的 132 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) 133 return e.value; 134 } 135 // 所有桶都找遍了,没找到想要的,所以返回null 136 return null; 137 } 138 139 // 如果要得到key为null的值,则通过这个获取 140 private V getForNullKey() { 141 // 遍历table[0]里的所有桶 142 for (Entry<K, V> e = table[0]; e != null; e = e.next) { 143 // 看看桶的key是不是null,是则返回相应值 144 if (e.key == null) 145 return e.value; 146 } 147 // 没找到返回null 148 return null; 149 } 150 151 // 如果此映射包含对于指定键的映射关系,则返回true 152 public boolean containsKey(Object key) { 153 return getEntry(key) != null; 154 } 155 156 // 通过key获取一个value 157 final Entry<K, V> getEntry(Object key) { 158 // 如果key为null,则hash为0,否则用hash函数预处理 159 int hash = (key == null) ? 0 : hash(key.hashCode()); 160 // 得到对应的hash值的桶,如果这个桶不是,就通过next获取下一个桶 161 for (Entry<K, V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { 162 Object k; 163 // 如果hash值相等,并且key相等则证明这个桶里的东西是我们想要的 164 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) 165 return e; 166 } 167 // 所有桶都找遍了,没找到想要的,所以返回null 168 return null; 169 } 170 171 // 在此映射中关联指定值与指定键。如果该映射以前包含了一个该键的映射关系,则旧值被替换 172 public V put(K key, V value) { 173 // 当key为null,调用putForNullKey方法,保存null与table第一个位置中,这是HashMap允许为null的原因 174 if (key == null) 175 return putForNullKey(value); 176 // 使用hash函数预处理hashCode,计算key的hash值 177 int hash = hash(key.hashCode()); 178 // 计算key hash 值在 table 数组中的位置 179 int i = indexFor(hash, table.length); 180 // 从i出开始迭代 e,找到 key 保存的位置 181 for (Entry<K, V> e = table[i]; e != null; e = e.next) { 182 Object k; 183 // 判断该条链上是否有hash值相同的(key相同) 184 // 若存在相同,则直接覆盖value,返回旧value 185 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 186 // 旧值 = 新值 187 V oldValue = e.value; 188 // 将要存储的value存进去 189 e.value = value; 190 e.recordAccess(this); 191 // 返回旧的value 192 return oldValue; 193 } 194 } 195 // 修改次数增加1 196 modCount++; 197 // 将key、value添加至i位置处 198 addEntry(hash, key, value, i); 199 return null; 200 } 201 202 // key为null怎么放value 203 private V putForNullKey(V value) { 204 // 遍历table[0]的所有桶 205 for (Entry<K, V> e = table[0]; e != null; e = e.next) { 206 // 如果key是null 207 if (e.key == null) { 208 // 取出oldValue,并存入value 209 V oldValue = e.value; 210 e.value = value; 211 e.recordAccess(this); 212 // 返回oldValue 213 return oldValue; 214 } 215 } 216 modCount++; 217 addEntry(0, null, value, 0); 218 return null; 219 } 220 221 // 看看需不需要创建新的桶 222 private void putForCreate(K key, V value) { 223 // 如果key为null,则定义hash为0,否则用hash函数预处理 224 int hash = (key == null) ? 0 : hash(key.hashCode()); 225 // 获取对应的索引 226 int i = indexFor(hash, table.length); 227 228 // 遍历所有桶 229 for (Entry<K, V> e = table[i]; e != null; e = e.next) { 230 Object k; 231 // 如果有hash相同,且key相同,那么则不需要创建新的桶,退出 232 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { 233 e.value = value; 234 return; 235 } 236 } 237 238 // 否则需要创建新的桶 239 createEntry(hash, key, value, i); 240 } 241 242 // 根据Map创建所有对应的桶 243 private void putAllForCreate(Map<? extends K, ? extends V> m) { 244 for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext();) { 245 Map.Entry<? extends K, ? extends V> e = i.next(); 246 putForCreate(e.getKey(), e.getValue()); 247 } 248 } 249 250 // 更具新的容量来resize这个HashMap 251 void resize(int newCapacity) { 252 // 保存oldTable 253 Entry[] oldTable = table; 254 // 保存旧的容量 255 int oldCapacity = oldTable.length; 256 // 如果旧的容量已经是系统默认最大容量了,那么将阈值设置成整形的最大值,退出 257 if (oldCapacity == MAXIMUM_CAPACITY) { 258 threshold = Integer.MAX_VALUE; 259 return; 260 } 261 262 // 根据新的容量新建一个table 263 Entry[] newTable = new Entry[newCapacity]; 264 // 将table转换成newTable 265 transfer(newTable); 266 // 将table设置newTable 267 table = newTable; 268 // 设置阈值 269 threshold = (int) (newCapacity * loadFactor); 270 } 271 272 // 将所有格子里的桶都放到新的table中 273 void transfer(Entry[] newTable) { 274 // 得到旧的table 275 Entry[] src = table; 276 // 得到新的容量 277 int newCapacity = newTable.length; 278 // 遍历src里面的所有格子 279 for (int j = 0; j < src.length; j++) { 280 // 取到格子里的桶(也就是链表) 281 Entry<K, V> e = src[j]; 282 // 如果e不为空 283 if (e != null) { 284 // 将当前格子设成null 285 src[j] = null; 286 // 遍历格子的所有桶 287 do { 288 // 取出下个桶 289 Entry<K, V> next = e.next; 290 // 寻找新的索引 291 int i = indexFor(e.hash, newCapacity); 292 // 设置e.next为newTable[i]保存的桶(也就是链表连接上) 293 e.next = newTable[i]; 294 // 将e设成newTable[i] 295 newTable[i] = e; 296 // 设置e为下一个桶 297 e = next; 298 } while (e != null); 299 } 300 } 301 } 302 303 // 将指定映射的所有映射关系复制到此映射中,这些映射关系将替换此映射目前针对指定映射中所有键的所有映射关系 304 public void putAll(Map<? extends K, ? extends V> m) { 305 // 看看需要复制多少个映射关系 306 int numKeysToBeAdded = m.size(); 307 if (numKeysToBeAdded == 0) 308 return; 309 310 // 如果要复制的映射关系比阈值还要多 311 if (numKeysToBeAdded > threshold) { 312 // 重新计算新的容量先resize 313 int targetCapacity = (int) (numKeysToBeAdded / loadFactor + 1); 314 if (targetCapacity > MAXIMUM_CAPACITY) 315 targetCapacity = MAXIMUM_CAPACITY; 316 int newCapacity = table.length; 317 while (newCapacity < targetCapacity) 318 newCapacity <<= 1; 319 if (newCapacity > table.length) 320 resize(newCapacity); 321 } 322 323 // 迭代将key-value映射放进该HashMap 324 for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext();) { 325 Map.Entry<? extends K, ? extends V> e = i.next(); 326 put(e.getKey(), e.getValue()); 327 } 328 } 329 330 // 从此映射中移除指定键的映射关系(如果存在) 331 public V remove(Object key) { 332 Entry<K, V> e = removeEntryForKey(key); 333 return (e == null ? null : e.value); 334 } 335 336 // 根据key删除桶,并返回对应value 337 final Entry<K, V> removeEntryForKey(Object key) { 338 int hash = (key == null) ? 0 : hash(key.hashCode()); 339 int i = indexFor(hash, table.length); 340 // 找到对应的格子 341 Entry<K, V> prev = table[i]; 342 Entry<K, V> e = prev; 343 344 // 遍历所有桶 345 while (e != null) { 346 Entry<K, V> next = e.next; 347 Object k; 348 // 如果找到对应的桶 349 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { 350 modCount++; 351 // size减1 352 size--; 353 // 如果第一个就是要删的桶 354 if (prev == e) 355 // 则table[i]等于下一个桶 356 table[i] = next; 357 else 358 // 否则上一个桶的下一个等于下一个桶 359 prev.next = next; 360 e.recordRemoval(this); 361 return e; 362 } 363 prev = e; 364 e = next; 365 } 366 367 return e; 368 } 369 370 // 根据桶来删除map里的值 371 final Entry<K, V> removeMapping(Object o) { 372 // 如果o不是Map.Entry的实例,则退出返回null 373 if (!(o instanceof Map.Entry)) 374 return null; 375 376 // 将o转成Map.Entry 377 Map.Entry<K, V> entry = (Map.Entry<K, V>) o; 378 // 得到他的key 379 Object key = entry.getKey(); 380 // 得到对应的hash 381 int hash = (key == null) ? 0 : hash(key.hashCode()); 382 // 得到对应的索引 383 int i = indexFor(hash, table.length); 384 Entry<K, V> prev = table[i]; 385 Entry<K, V> e = prev; 386 387 // 遍历所有桶 388 while (e != null) { 389 Entry<K, V> next = e.next; 390 // 如果找到对应的桶,则删掉它 391 if (e.hash == hash && e.equals(entry)) { 392 modCount++; 393 size--; 394 if (prev == e) 395 table[i] = next; 396 else 397 prev.next = next; 398 e.recordRemoval(this); 399 return e; 400 } 401 prev = e; 402 e = next; 403 } 404 405 // 并返回该桶 406 return e; 407 } 408 409 // 从此映射中移除所有映射关系。此调用返回后,映射将为空 410 public void clear() { 411 modCount++; 412 Entry[] tab = table; 413 // 遍历table中的所有格子,然偶后设为null 414 for (int i = 0; i < tab.length; i++) 415 tab[i] = null; 416 // 设置size为0 417 size = 0; 418 } 419 420 // 如果此映射将一个或多个键映射到指定值,则返回 true 421 public boolean containsValue(Object value) { 422 // 如果value为空,则返回containsNullValue函数的返回值 423 if (value == null) 424 return containsNullValue(); 425 426 Entry[] tab = table; 427 // 遍历table所有格子(链表) 428 for (int i = 0; i < tab.length; i++) 429 // 遍历链表中的每个桶 430 for (Entry e = tab[i]; e != null; e = e.next) 431 // 如果值相同,则返回true 432 if (value.equals(e.value)) 433 return true; 434 // 否则返回false 435 return false; 436 } 437 438 // 对value为null的处理,这里没什么特别的 439 private boolean containsNullValue() { 440 Entry[] tab = table; 441 for (int i = 0; i < tab.length; i++) 442 for (Entry e = tab[i]; e != null; e = e.next) 443 if (e.value == null) 444 return true; 445 return false; 446 } 447 448 // 返回此 HashMap 实例的浅表副本:并不复制键和值本身 449 public Object clone() { 450 HashMap<K, V> result = null; 451 try { 452 result = (HashMap<K, V>) super.clone(); 453 } catch (CloneNotSupportedException e) { 454 // assert false; 455 } 456 result.table = new Entry[table.length]; 457 result.entrySet = null; 458 result.modCount = 0; 459 result.size = 0; 460 result.init(); 461 result.putAllForCreate(this); 462 463 return result; 464 } 465 466 // 内置class输入对象,也就是我们说的桶 467 static class Entry<K, V> implements Map.Entry<K, V> { 468 final K key; 469 V value; 470 Entry<K, V> next; 471 final int hash; 472 473 // 构造函数 474 Entry(int h, K k, V v, Entry<K, V> n) { 475 value = v; 476 next = n; 477 key = k; 478 hash = h; 479 } 480 481 // 返回key 482 public final K getKey() { 483 return key; 484 } 485 486 // 返回value 487 public final V getValue() { 488 return value; 489 } 490 491 // 设置value 492 public final V setValue(V newValue) { 493 V oldValue = value; 494 value = newValue; 495 return oldValue; 496 } 497 498 // 是否相同 499 public final boolean equals(Object o) { 500 // 如果o不是Map.Entry的实例,那么肯定不相同了 501 if (!(o instanceof Map.Entry)) 502 return false; 503 // 将o转成Map.Entry 504 Map.Entry e = (Map.Entry) o; 505 // 得到key和value对比是否相同,相同则为true 506 Object k1 = getKey(); 507 Object k2 = e.getKey(); 508 if (k1 == k2 || (k1 != null && k1.equals(k2))) { 509 Object v1 = getValue(); 510 Object v2 = e.getValue(); 511 if (v1 == v2 || (v1 != null && v1.equals(v2))) 512 return true; 513 } 514 // 否则为false 515 return false; 516 } 517 518 // hashCode 519 public final int hashCode() { 520 return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); 521 } 522 523 // 返回String 524 public final String toString() { 525 return getKey() + "=" + getValue(); 526 } 527 528 // 使用该方法证明该key已经在该map中 529 void recordAccess(HashMap<K, V> m) { 530 } 531 532 // 该方法记录该key已经被移除了 533 void recordRemoval(HashMap<K, V> m) { 534 } 535 } 536 537 // 添加一个新的桶来保存该key和value 538 void addEntry(int hash, K key, V value, int bucketIndex) { 539 // 获取bucketIndex处的Entry 540 Entry<K, V> e = table[bucketIndex]; 541 // 将新创建的 Entry 放入 bucketIndex 索引处,并让新的 Entry 指向原来的 Entry 542 table[bucketIndex] = new Entry<K, V>(hash, key, value, e); 543 // 若HashMap中元素的个数超过极限了,则容量扩大两倍 544 if (size++ >= threshold) 545 // 调整容量 546 resize(2 * table.length); 547 } 548 549 // 新建一个桶,该方法不需要判断是否超过阈值 550 void createEntry(int hash, K key, V value, int bucketIndex) { 551 Entry<K, V> e = table[bucketIndex]; 552 table[bucketIndex] = new Entry<K, V>(hash, key, value, e); 553 size++; 554 } 555 556 // 内部class HashIterator迭代器 557 private abstract class HashIterator<E> implements Iterator<E> { 558 Entry<K, V> next; // 下一个桶 559 int expectedModCount; // 保护HashMap没有变更 560 int index; // 当前的索引 561 Entry<K, V> current; // 当前的桶 562 563 // 构造方法 564 HashIterator() { 565 // 保存modCount,因为如果HashMap进行了任何操作modCount都会增加,所以如果发现modCount变化了,就可以抛出失败 566 expectedModCount = modCount; 567 // 进入第一个桶 568 if (size > 0) { 569 Entry[] t = table; 570 while (index < t.length && (next = t[index++]) == null) 571 ; 572 } 573 } 574 575 // 看看有没有下一个桶 576 public final boolean hasNext() { 577 return next != null; 578 } 579 580 // 获取下一个桶 581 final Entry<K, V> nextEntry() { 582 // modCount变化了,抛出失败 583 if (modCount != expectedModCount) 584 throw new ConcurrentModificationException(); 585 // 得到next 586 Entry<K, V> e = next; 587 // 如果next为空,抛出失败 588 if (e == null) 589 throw new NoSuchElementException(); 590 591 // 如果next.next为空,将next定义为下一个格子中的桶,否则为该格子的下一个桶 592 if ((next = e.next) == null) { 593 Entry[] t = table; 594 while (index < t.length && (next = t[index++]) == null) 595 ; 596 } 597 // 给current赋值 598 current = e; 599 // 返回e 600 return e; 601 } 602 603 // 删除 604 public void remove() { 605 // 如果当前为空,抛出 606 if (current == null) 607 throw new IllegalStateException(); 608 // modCount变化了,抛出失败 609 if (modCount != expectedModCount) 610 throw new ConcurrentModificationException(); 611 // 获得当前的key 612 Object k = current.key; 613 // 设置current为null 614 current = null; 615 // 删除掉对应key的元素 616 HashMap.this.removeEntryForKey(k); 617 // 重置expectedModCount 618 expectedModCount = modCount; 619 } 620 621 } 622 623 // 内部class ValueIterator迭代器,我们可以看到修改了next方法 624 private final class ValueIterator extends HashIterator<V> { 625 public V next() { 626 return nextEntry().value; 627 } 628 } 629 630 // 内部class KeyIterator迭代器,我们可以看到修改了next方法 631 private final class KeyIterator extends HashIterator<K> { 632 public K next() { 633 return nextEntry().getKey(); 634 } 635 } 636 637 // 内部class EntryIterator迭代器,我们可以看到修改了next方法 638 private final class EntryIterator extends HashIterator<Map.Entry<K, V>> { 639 public Map.Entry<K, V> next() { 640 return nextEntry(); 641 } 642 } 643 644 // 定义对应的 iterator() 方法 645 Iterator<K> newKeyIterator() { 646 return new KeyIterator(); 647 } 648 649 Iterator<V> newValueIterator() { 650 return new ValueIterator(); 651 } 652 653 Iterator<Map.Entry<K, V>> newEntryIterator() { 654 return new EntryIterator(); 655 } 656 657 private transient Set<Map.Entry<K, V>> entrySet = null; 658 659 /** 660 * 返回此映射中所包含的键的 Set 视图。 该 set 受映射的支持,所以对映射的更改将反映在该 set 中, 反之亦然。如果在对 set 661 * 进行迭代的同时修改了映射(通过迭代器自己的 remove 操作除外), 则迭代结果是不确定的。该 set 支持元素的移除,通过 662 * Iterator.remove、Set.remove、removeAll、retainAll 和 clear 操作 663 * 可从该映射中移除相应的映射关系。它不支持 add 或 addAll 操作。 664 */ 665 public Set<K> keySet() { 666 Set<K> ks = keySet(); 667 // 如果keySet为空,则通过新建一个KeySet 668 return (ks != null ? ks : (ks = new KeySet())); 669 } 670 671 // 内部类KeySet 672 private final class KeySet extends AbstractSet<K> { 673 // 定义iterator方法 674 public Iterator<K> iterator() { 675 return newKeyIterator(); 676 } 677 678 // 定义size 679 public int size() { 680 return size; 681 } 682 683 // 定义contains 684 public boolean contains(Object o) { 685 return containsKey(o); 686 } 687 688 // 定义remove 689 public boolean remove(Object o) { 690 return HashMap.this.removeEntryForKey(o) != null; 691 } 692 693 // 定义clear 694 public void clear() { 695 HashMap.this.clear(); 696 } 697 } 698 699 /** 700 * 返回此映射所包含的值的 Collection 视图。 该 collection 受映射的支持,所以对映射的更改将反映在该 collection 701 * 中, 反之亦然。如果在对 collection 进行迭代的同时修改了映射(通过迭代器自己的 remove 操作除外), 则迭代结果是不确定的。该 702 * collection 支持元素的移除, 通过 703 * Iterator.remove、Collection.remove、removeAll、retainAll 和 clear 操作 704 * 可从该映射中移除相应的映射关系。它不支持 add 或 addAll 操作。 705 */ 706 public Collection<V> values() { 707 Collection<V> vs = values(); 708 return (vs != null ? vs : (vs = new Values())); 709 } 710 711 // 内部类Values 712 private final class Values extends AbstractCollection<V> { 713 public Iterator<V> iterator() { 714 return newValueIterator(); 715 } 716 717 public int size() { 718 return size; 719 } 720 721 public boolean contains(Object o) { 722 return containsValue(o); 723 } 724 725 public void clear() { 726 HashMap.this.clear(); 727 } 728 } 729 730 /** 731 * 返回此映射所包含的映射关系的 Set 视图。 该 set 受映射支持,所以对映射的更改将反映在此 set 中, 反之亦然。如果在对 set 732 * 进行迭代的同时修改了映射 (通过迭代器自己的 remove 操作,或者通过在该迭代器返回的映射项上执行 setValue 操作除外), 733 * 则迭代结果是不确定的。该 set 支持元素的移除, 通过 734 * Iterator.remove、Set.remove、removeAll、retainAll 和 clear 操作 735 * 可从该映射中移除相应的映射关系。它不支持 add 或 addAll 操作。 736 */ 737 public Set<Map.Entry<K, V>> entrySet() { 738 return entrySet0(); 739 } 740 741 private Set<Map.Entry<K, V>> entrySet0() { 742 Set<Map.Entry<K, V>> es = entrySet; 743 return es != null ? es : (entrySet = new EntrySet()); 744 } 745 746 // 内部类EntrySet 747 private final class EntrySet extends AbstractSet<Map.Entry<K, V>> { 748 public Iterator<Map.Entry<K, V>> iterator() { 749 return newEntryIterator(); 750 } 751 752 public boolean contains(Object o) { 753 if (!(o instanceof Map.Entry)) 754 return false; 755 Map.Entry<K, V> e = (Map.Entry<K, V>) o; 756 Entry<K, V> candidate = getEntry(e.getKey()); 757 return candidate != null && candidate.equals(e); 758 } 759 760 public boolean remove(Object o) { 761 return removeMapping(o) != null; 762 } 763 764 public int size() { 765 return size; 766 } 767 768 public void clear() { 769 HashMap.this.clear(); 770 } 771 } 772 773 // 序列化方法 774 private void writeObject(java.io.ObjectOutputStream s) throws IOException { 775 Iterator<Map.Entry<K, V>> i = (size > 0) ? entrySet0().iterator() : null; 776 777 s.defaultWriteObject(); 778 779 s.writeInt(table.length); 780 781 s.writeInt(size); 782 783 if (i != null) { 784 while (i.hasNext()) { 785 Map.Entry<K, V> e = i.next(); 786 s.writeObject(e.getKey()); 787 s.writeObject(e.getValue()); 788 } 789 } 790 } 791 792 private static final long serialVersionUID = 362498820763181265L; 793 794 // 通过序列读取对象 795 private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { 796 s.defaultReadObject(); 797 798 int numBuckets = s.readInt(); 799 table = new Entry[numBuckets]; 800 801 init(); 802 803 int size = s.readInt(); 804 805 for (int i = 0; i < size; i++) { 806 K key = (K) s.readObject(); 807 V value = (V) s.readObject(); 808 putForCreate(key, value); 809 } 810 } 811 812 int capacity() { 813 return table.length; 814 } 815 816 float loadFactor() { 817 return loadFactor; 818 } 819 }