HashMap源码分析
本文的写作,参考了兰亭风雨的相关博客。
读懂HashMap需要具备一些基础知识
一、基础知识
1、散列
参考【数据结构与算法分析java语言描述】第五章【散列】,
这里我们不讨论具体的哈希的原理。
1)散列表数据结构只不过是一个包含项(item)的具有固定大小的数组。
2)散列数组中,每一个项,叫做一个“桶”,英文bucket,它的下标叫bucketIndex。HashMap的结构如下,

HashMap就是一个散列结构,具体到它的内部,就是名为table的Entry数组,代表这个HashMap。table的下标,是每一个Entry的key的hash值与table的length做“与运算”得到的int值(这个功能是indexFor()实现的)。
2、链表
HashMap中的Entry<K,V>,是一个静态内部类,它是一个链表结构;每一个Entry保存自身的key,value,hashCode,以及指向下一个的Entry。
二、indexFor函数的说明:
indexFor函数,参数h代表,hashMap每次put的时候的key的hash值,length代码hashMap当前的大小。
indexFor作用是根据当前key的hash来确定,这一个放入HashMap数组中的Entry应该出于数组的哪一个位置(index)中?
1 static int indexFor(int h, int length) { 2 // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2"; 3 return h & (length-1); 4 }
必要条件是,这个位置bucketIndex肯定不能超过数组大小。于是,最容易的方法是肯定取模。即int bucketIndex = hashNumber % length;然而这个方法效率不高。
另一种方法:
任意正整数a,除以2^n,所得余数c,有如下公式 a = c + k * 2^n(即 被除数= 余数 + 商*除数,这里除数2^n)
把a转换为二进制数,如下,

当除数是2^n,将被除数a的二进制数,右移n位,得到的数就是商,而被移除掉的数字就是余数。
也就是说我们只要得到上图红线右侧的内容就是余数,那么只要将原数字a & (2^n - 1)就可以。
即indexFor()中的
return h & (length-1);
Integer.bitCount(int param),获取param的二进制数中1的个数。
Integer.highestOneBit(int param),获取param的二进制数中,最左侧第一个1,所代表的int值。也就是不大于当前param的最大的2的n次方。
以下是全部代码分析,必要的地方做了注释,
1 package java.util; 2 import java.io.*; 3 4 public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable{ 5 6 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 7 8 static final int MAXIMUM_CAPACITY = 1 << 30; 9 static final float DEFAULT_LOAD_FACTOR = 0.75f; 10 // 空Entry数组 11 static final Entry<?,?>[] EMPTY_TABLE = {}; 12 // 初始化table 13 transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; 14 // 保存的Entry数量 15 transient int size; 16 // 当threshold大于size(Entry的数量)时,调用resize, 17 int threshold; 18 19 final float loadFactor; 20 // 修改次数 21 transient int modCount; 22 23 static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE; 24 private static class Holder { 25 static final int ALTERNATIVE_HASHING_THRESHOLD; 26 27 static { 28 String altThreshold = java.security.AccessController.doPrivileged( 29 new sun.security.action.GetPropertyAction( 30 "jdk.map.althashing.threshold")); 31 32 int threshold; 33 try { 34 threshold = (null != altThreshold) 35 ? Integer.parseInt(altThreshold) 36 : ALTERNATIVE_HASHING_THRESHOLD_DEFAULT; 37 38 // disable alternative hashing if -1 39 if (threshold == -1) { 40 threshold = Integer.MAX_VALUE; 41 } 42 43 if (threshold < 0) { 44 throw new IllegalArgumentException("value must be positive integer."); 45 } 46 } catch(IllegalArgumentException failed) { 47 throw new Error("Illegal value for 'jdk.map.althashing.threshold'", failed); 48 } 49 50 ALTERNATIVE_HASHING_THRESHOLD = threshold; 51 } 52 } 53 54 transient int hashSeed = 0; 55 56 // HashMap初始化,table仍然是EMPTY_TABLE,即空Entry数组 57 // threshold赋值为initialCapacity,默认情况这个值是16 58 public HashMap(int initialCapacity, float loadFactor) { 59 if (initialCapacity < 0) 60 throw new IllegalArgumentException("Illegal initial capacity: " + 61 initialCapacity); 62 if (initialCapacity > MAXIMUM_CAPACITY) 63 initialCapacity = MAXIMUM_CAPACITY; 64 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 65 throw new IllegalArgumentException("Illegal load factor: " + 66 loadFactor); 67 68 this.loadFactor = loadFactor; 69 threshold = initialCapacity; 70 init(); 71 } 72 73 public HashMap(int initialCapacity) { 74 this(initialCapacity, DEFAULT_LOAD_FACTOR); 75 } 76 77 public HashMap() { 78 this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); 79 } 80 81 public HashMap(Map<? extends K, ? extends V> m) { 82 this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, 83 DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); 84 inflateTable(threshold); 85 86 putAllForCreate(m); 87 } 88 89 // 取得当前大于number的最小的2的n次方 90 // number >= MAXIMUM_CAPACITY = MAXIMUM_CAPACITY 91 // number <= 1 = 1 92 // 1 < number < MAXIMUM_CAPACITY = 大于当前number的最小的2的n次方 93 private static int roundUpToPowerOf2(int number) { 94 // assert number >= 0 : "number must be non-negative"; 95 int rounded = number >= MAXIMUM_CAPACITY 96 ? MAXIMUM_CAPACITY 97 : (rounded = Integer.highestOneBit(number)) != 0 98 ? (Integer.bitCount(number) > 1) ? rounded << 1 : rounded 99 : 1; 100 101 return rounded; 102 } 103 104 //上面版本不太好阅读,翻译成以下版本。 105 private static int roundUpToPowerOf2(int number){ 106 int rounded; 107 if(number >= MAXIMUM_CAPACITY){ 108 rounded = MAXIMUM_CAPACITY; 109 }else{ 110 //Integer.highestOneBit,取大于number的最小的2的幂。 111 if( (rounded = Integer.highestOneBit(number)) != 0){//如果number不为0 112 if(Integer.bitCount(number) > 1){//如果number>1 113 //注意,此时rounded已经是大于number的最小的2的幂。 114 rounded = rounded << 1; //将上述rounded左移一位,即乘以2。 115 }else{ 116 rounded = rounded; 117 } 118 }else{//如果number为0 119 rounded = 1; 120 } 121 } 122 return rounded; 123 } 124 125 126 // 1、将table变量指向一个新Entry数组,数组length为大于参数的最小2的n次方 127 // 2、修改threshold,为 数组大小* loadFactor 128 // 3、修正hashSeed 129 private void inflateTable(int toSize) { 130 // Find a power of 2 >= toSize 131 int capacity = roundUpToPowerOf2(toSize); 132 133 threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); 134 table = new Entry[capacity]; 135 initHashSeedAsNeeded(capacity); 136 } 137 138 void init() { 139 } 140 // initHashSeedAsNeeded,1:修正hashSeed;2:返回boolean 141 final boolean initHashSeedAsNeeded(int capacity) { 142 boolean currentAltHashing = hashSeed != 0; 143 boolean useAltHashing = sun.misc.VM.isBooted() && 144 (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); 145 boolean switching = currentAltHashing ^ useAltHashing; 146 if (switching) { 147 hashSeed = useAltHashing 148 ? sun.misc.Hashing.randomHashSeed(this) 149 : 0; 150 } 151 return switching; 152 } 153 154 final int hash(Object k) { 155 int h = hashSeed; 156 if (0 != h && k instanceof String) { 157 return sun.misc.Hashing.stringHash32((String) k); 158 } 159 160 h ^= k.hashCode(); 161 162 h ^= (h >>> 20) ^ (h >>> 12); 163 return h ^ (h >>> 7) ^ (h >>> 4); 164 } 165 // 将key的hash值与table的length做与运算,得到的int值即为该key在Entry数组中的位置,即bucketIndex。 166 static int indexFor(int h, int length) { 167 // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2"; 168 return h & (length-1); 169 } 170 171 public int size() { 172 return size; 173 } 174 175 public boolean isEmpty() { 176 return size == 0; 177 } 178 179 public V get(Object key) { 180 if (key == null) 181 return getForNullKey(); 182 Entry<K,V> entry = getEntry(key); 183 184 return null == entry ? null : entry.getValue(); 185 } 186 187 private V getForNullKey() { 188 if (size == 0) { 189 return null; 190 } 191 for (Entry<K,V> e = table[0]; e != null; e = e.next) { 192 if (e.key == null) 193 return e.value; 194 } 195 return null; 196 } 197 198 public boolean containsKey(Object key) { 199 return getEntry(key) != null; 200 } 201 202 // 1、根据key值获取hash值 203 // 2、在Entry数组中找到指定的bucket,取出其中的Entry(链表), 204 // 3、遍历这个Entry,如果Entry链表中存在一个Entry的key与传入的key相同,则返回这个Entry 205 final Entry<K,V> getEntry(Object key) { 206 if (size == 0) { 207 return null; 208 } 209 210 int hash = (key == null) ? 0 : hash(key); 211 for (Entry<K,V> e = table[indexFor(hash, table.length)]; 212 e != null; 213 e = e.next) { 214 Object k; 215 if (e.hash == hash && 216 ((k = e.key) == key || (key != null && key.equals(k)))) 217 return e; 218 } 219 return null; 220 } 221 222 // 1、判断table是否为null,若是则调用inflateTable(),参数threshold的值为16(在构造函数中赋值), 223 // 调用roundUpToPowerOf2(大于当前数值的最小的2的n次方)确定capacity,然后new一个Entry数组 224 // 调整threshold的值,调整hashseed 225 // 2、计算key的hash值,调用indexFor确定此key在Entry数组中的bucketIndex 226 // 3、取出Entry数组中的第一个Entry(链表),遍历这个链表, 227 // 3.1、若存在一个Entry的key等于当前key则把这个Entry的value修改,并把old value返回出去,put函数终止 228 // 3.2、若不存在,modCount++,调用addEntry 229 // 3.2.1、判断size是否大于threshold,若是则调用resize(), 230 // 3.2.2、调用createEntry(),先根据bucketIndex取出Entry数组中的Entry(可能为null) 231 // 然后new一个Entry,并把刚取出的Entry作为新Entry的next, 232 // size++(Entry的数量) 233 public V put(K key, V value) { 234 if (table == EMPTY_TABLE) { 235 inflateTable(threshold); 236 } 237 if (key == null) 238 return putForNullKey(value); 239 int hash = hash(key); 240 int i = indexFor(hash, table.length); 241 for (Entry<K,V> e = table[i]; e != null; e = e.next) { 242 Object k; 243 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 244 V oldValue = e.value; 245 e.value = value; 246 e.recordAccess(this); 247 return oldValue; 248 } 249 } 250 251 modCount++; 252 addEntry(hash, key, value, i); 253 return null; 254 } 255 256 private V putForNullKey(V value) { 257 for (Entry<K,V> e = table[0]; e != null; e = e.next) { 258 if (e.key == null) { 259 V oldValue = e.value; 260 e.value = value; 261 e.recordAccess(this); 262 return oldValue; 263 } 264 } 265 modCount++; 266 addEntry(0, null, value, 0); 267 return null; 268 } 269 270 private void putForCreate(K key, V value) { 271 int hash = null == key ? 0 : hash(key); 272 int i = indexFor(hash, table.length); 273 274 for (Entry<K,V> e = table[i]; e != null; e = e.next) { 275 Object k; 276 if (e.hash == hash && 277 ((k = e.key) == key || (key != null && key.equals(k)))) { 278 e.value = value; 279 return; 280 } 281 } 282 283 createEntry(hash, key, value, i); 284 } 285 286 private void putAllForCreate(Map<? extends K, ? extends V> m) { 287 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) 288 putForCreate(e.getKey(), e.getValue()); 289 } 290 291 // 1、从暴露给外界的函数看,HashMap中调用resize()地方只有两处1:put();2:putAll() 292 // put()传给resize的参数是Entry数组的length*2;putAll不知道 293 // 2、resize()根据传入的参数newCapacity,new一个新Entry数组, 294 // 3、调用initHashSeedAsNeeded,修正hashSeed,并返回, 295 // 4、调用transfer()将旧Entry数组中的内容全部copy到新Entry数组 296 // 5、调整threshold的值newCapacity * loadFactor 297 void resize(int newCapacity) { 298 Entry[] oldTable = table; 299 int oldCapacity = oldTable.length; 300 if (oldCapacity == MAXIMUM_CAPACITY) { 301 threshold = Integer.MAX_VALUE; 302 return; 303 } 304 305 Entry[] newTable = new Entry[newCapacity]; 306 transfer(newTable, initHashSeedAsNeeded(newCapacity)); 307 table = newTable; 308 threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1); 309 } 310 311 void transfer(Entry[] newTable, boolean rehash) { 312 int newCapacity = newTable.length; 313 for (Entry<K,V> e : table) { 314 while(null != e) { 315 Entry<K,V> next = e.next; 316 if (rehash) { 317 e.hash = null == e.key ? 0 : hash(e.key); 318 } 319 int i = indexFor(e.hash, newCapacity); 320 e.next = newTable[i]; 321 newTable[i] = e; 322 e = next; 323 } 324 } 325 } 326 327 public void putAll(Map<? extends K, ? extends V> m) { 328 int numKeysToBeAdded = m.size(); 329 if (numKeysToBeAdded == 0) 330 return; 331 332 if (table == EMPTY_TABLE) { 333 inflateTable((int) Math.max(numKeysToBeAdded * loadFactor, threshold)); 334 } 335 336 if (numKeysToBeAdded > threshold) { 337 int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); 338 if (targetCapacity > MAXIMUM_CAPACITY) 339 targetCapacity = MAXIMUM_CAPACITY; 340 int newCapacity = table.length; 341 while (newCapacity < targetCapacity) 342 newCapacity <<= 1; 343 if (newCapacity > table.length) 344 resize(newCapacity); 345 } 346 347 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) 348 put(e.getKey(), e.getValue()); 349 } 350 351 public V remove(Object key) { 352 Entry<K,V> e = removeEntryForKey(key); 353 return (e == null ? null : e.value); 354 } 355 356 final Entry<K,V> removeEntryForKey(Object key) { 357 if (size == 0) { 358 return null; 359 } 360 int hash = (key == null) ? 0 : hash(key); 361 int i = indexFor(hash, table.length); 362 Entry<K,V> prev = table[i]; 363 Entry<K,V> e = prev; 364 365 while (e != null) { 366 Entry<K,V> next = e.next; 367 Object k; 368 if (e.hash == hash && 369 ((k = e.key) == key || (key != null && key.equals(k)))) { 370 modCount++; 371 size--; 372 if (prev == e) 373 table[i] = next; 374 else 375 prev.next = next; 376 e.recordRemoval(this); 377 return e; 378 } 379 prev = e; 380 e = next; 381 } 382 383 return e; 384 } 385 386 final Entry<K,V> removeMapping(Object o) { 387 if (size == 0 || !(o instanceof Map.Entry)) 388 return null; 389 390 Map.Entry<K,V> entry = (Map.Entry<K,V>) o; 391 Object key = entry.getKey(); 392 int hash = (key == null) ? 0 : hash(key); 393 int i = indexFor(hash, table.length); 394 Entry<K,V> prev = table[i]; 395 Entry<K,V> e = prev; 396 397 while (e != null) { 398 Entry<K,V> next = e.next; 399 if (e.hash == hash && e.equals(entry)) { 400 modCount++; 401 size--; 402 if (prev == e) 403 table[i] = next; 404 else 405 prev.next = next; 406 e.recordRemoval(this); 407 return e; 408 } 409 prev = e; 410 e = next; 411 } 412 413 return e; 414 } 415 416 public void clear() { 417 modCount++; 418 Arrays.fill(table, null); 419 size = 0; 420 } 421 422 public boolean containsValue(Object value) { 423 if (value == null) 424 return containsNullValue(); 425 426 Entry[] tab = table; 427 for (int i = 0; i < tab.length ; i++) 428 for (Entry e = tab[i] ; e != null ; e = e.next) 429 if (value.equals(e.value)) 430 return true; 431 return false; 432 } 433 434 private boolean containsNullValue() { 435 Entry[] tab = table; 436 for (int i = 0; i < tab.length ; i++) 437 for (Entry e = tab[i] ; e != null ; e = e.next) 438 if (e.value == null) 439 return true; 440 return false; 441 } 442 443 public Object clone() { 444 HashMap<K,V> result = null; 445 try { 446 result = (HashMap<K,V>)super.clone(); 447 } catch (CloneNotSupportedException e) { 448 // assert false; 449 } 450 if (result.table != EMPTY_TABLE) { 451 result.inflateTable(Math.min( 452 (int) Math.min( 453 size * Math.min(1 / loadFactor, 4.0f), 454 // we have limits... 455 HashMap.MAXIMUM_CAPACITY), 456 table.length)); 457 } 458 result.entrySet = null; 459 result.modCount = 0; 460 result.size = 0; 461 result.init(); 462 result.putAllForCreate(this); 463 464 return result; 465 } 466 467 static class Entry<K,V> implements Map.Entry<K,V> { 468 final K key; 469 V value; 470 Entry<K,V> next; 471 int hash; 472 473 /** 474 * Creates new entry. 475 */ 476 Entry(int h, K k, V v, Entry<K,V> n) { 477 value = v; 478 next = n; 479 key = k; 480 hash = h; 481 } 482 483 public final K getKey() { 484 return key; 485 } 486 487 public final V getValue() { 488 return value; 489 } 490 491 public final V setValue(V newValue) { 492 V oldValue = value; 493 value = newValue; 494 return oldValue; 495 } 496 497 public final boolean equals(Object o) { 498 if (!(o instanceof Map.Entry)) 499 return false; 500 Map.Entry e = (Map.Entry)o; 501 Object k1 = getKey(); 502 Object k2 = e.getKey(); 503 if (k1 == k2 || (k1 != null && k1.equals(k2))) { 504 Object v1 = getValue(); 505 Object v2 = e.getValue(); 506 if (v1 == v2 || (v1 != null && v1.equals(v2))) 507 return true; 508 } 509 return false; 510 } 511 512 public final int hashCode() { 513 return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue()); 514 } 515 516 public final String toString() { 517 return getKey() + "=" + getValue(); 518 } 519 520 void recordAccess(HashMap<K,V> m) { 521 } 522 523 void recordRemoval(HashMap<K,V> m) { 524 } 525 } 526 527 void addEntry(int hash, K key, V value, int bucketIndex) { 528 if ((size >= threshold) && (null != table[bucketIndex])) { 529 resize(2 * table.length); 530 hash = (null != key) ? hash(key) : 0; 531 bucketIndex = indexFor(hash, table.length); 532 } 533 534 createEntry(hash, key, value, bucketIndex); 535 } 536 537 538 void createEntry(int hash, K key, V value, int bucketIndex) { 539 Entry<K,V> e = table[bucketIndex]; 540 table[bucketIndex] = new Entry<>(hash, key, value, e); 541 size++; 542 } 543 544 private abstract class HashIterator<E> implements Iterator<E> { 545 Entry<K,V> next; // next entry to return 546 int expectedModCount; // For fast-fail 547 int index; // current slot 548 Entry<K,V> current; // current entry 549 550 HashIterator() { 551 expectedModCount = modCount; 552 if (size > 0) { // advance to first entry 553 Entry[] t = table; 554 while (index < t.length && (next = t[index++]) == null) 555 ; 556 } 557 } 558 559 public final boolean hasNext() { 560 return next != null; 561 } 562 563 final Entry<K,V> nextEntry() { 564 if (modCount != expectedModCount) 565 throw new ConcurrentModificationException(); 566 Entry<K,V> e = next; 567 if (e == null) 568 throw new NoSuchElementException(); 569 570 if ((next = e.next) == null) { 571 Entry[] t = table; 572 while (index < t.length && (next = t[index++]) == null) 573 ; 574 } 575 current = e; 576 return e; 577 } 578 579 public void remove() { 580 if (current == null) 581 throw new IllegalStateException(); 582 if (modCount != expectedModCount) 583 throw new ConcurrentModificationException(); 584 Object k = current.key; 585 current = null; 586 HashMap.this.removeEntryForKey(k); 587 expectedModCount = modCount; 588 } 589 } 590 591 private final class ValueIterator extends HashIterator<V> { 592 public V next() { 593 return nextEntry().value; 594 } 595 } 596 597 private final class KeyIterator extends HashIterator<K> { 598 public K next() { 599 return nextEntry().getKey(); 600 } 601 } 602 603 private final class EntryIterator extends HashIterator<Map.Entry<K,V>> { 604 public Map.Entry<K,V> next() { 605 return nextEntry(); 606 } 607 } 608 609 // Subclass overrides these to alter behavior of views' iterator() method 610 Iterator<K> newKeyIterator() { 611 return new KeyIterator(); 612 } 613 Iterator<V> newValueIterator() { 614 return new ValueIterator(); 615 } 616 Iterator<Map.Entry<K,V>> newEntryIterator() { 617 return new EntryIterator(); 618 } 619 620 621 // Views 622 623 private transient Set<Map.Entry<K,V>> entrySet = null; 624 625 public Set<K> keySet() { 626 Set<K> ks = keySet; 627 return (ks != null ? ks : (keySet = new KeySet())); 628 } 629 630 private final class KeySet extends AbstractSet<K> { 631 public Iterator<K> iterator() { 632 return newKeyIterator(); 633 } 634 public int size() { 635 return size; 636 } 637 public boolean contains(Object o) { 638 return containsKey(o); 639 } 640 public boolean remove(Object o) { 641 return HashMap.this.removeEntryForKey(o) != null; 642 } 643 public void clear() { 644 HashMap.this.clear(); 645 } 646 } 647 648 public Collection<V> values() { 649 Collection<V> vs = values; 650 return (vs != null ? vs : (values = new Values())); 651 } 652 653 private final class Values extends AbstractCollection<V> { 654 public Iterator<V> iterator() { 655 return newValueIterator(); 656 } 657 public int size() { 658 return size; 659 } 660 public boolean contains(Object o) { 661 return containsValue(o); 662 } 663 public void clear() { 664 HashMap.this.clear(); 665 } 666 } 667 668 public Set<Map.Entry<K,V>> entrySet() { 669 return entrySet0(); 670 } 671 672 private Set<Map.Entry<K,V>> entrySet0() { 673 Set<Map.Entry<K,V>> es = entrySet; 674 return es != null ? es : (entrySet = new EntrySet()); 675 } 676 677 private final class EntrySet extends AbstractSet<Map.Entry<K,V>> { 678 public Iterator<Map.Entry<K,V>> iterator() { 679 return newEntryIterator(); 680 } 681 public boolean contains(Object o) { 682 if (!(o instanceof Map.Entry)) 683 return false; 684 Map.Entry<K,V> e = (Map.Entry<K,V>) o; 685 Entry<K,V> candidate = getEntry(e.getKey()); 686 return candidate != null && candidate.equals(e); 687 } 688 public boolean remove(Object o) { 689 return removeMapping(o) != null; 690 } 691 public int size() { 692 return size; 693 } 694 public void clear() { 695 HashMap.this.clear(); 696 } 697 } 698 699 private void writeObject(java.io.ObjectOutputStream s) 700 throws IOException 701 { 702 // Write out the threshold, loadfactor, and any hidden stuff 703 s.defaultWriteObject(); 704 705 // Write out number of buckets 706 if (table==EMPTY_TABLE) { 707 s.writeInt(roundUpToPowerOf2(threshold)); 708 } else { 709 s.writeInt(table.length); 710 } 711 712 // Write out size (number of Mappings) 713 s.writeInt(size); 714 715 // Write out keys and values (alternating) 716 if (size > 0) { 717 for(Map.Entry<K,V> e : entrySet0()) { 718 s.writeObject(e.getKey()); 719 s.writeObject(e.getValue()); 720 } 721 } 722 } 723 724 private static final long serialVersionUID = 362498820763181265L; 725 726 private void readObject(java.io.ObjectInputStream s) 727 throws IOException, ClassNotFoundException 728 { 729 // Read in the threshold (ignored), loadfactor, and any hidden stuff 730 s.defaultReadObject(); 731 if (loadFactor <= 0 || Float.isNaN(loadFactor)) { 732 throw new InvalidObjectException("Illegal load factor: " + 733 loadFactor); 734 } 735 736 // set other fields that need values 737 table = (Entry<K,V>[]) EMPTY_TABLE; 738 739 // Read in number of buckets 740 s.readInt(); // ignored. 741 742 // Read number of mappings 743 int mappings = s.readInt(); 744 if (mappings < 0) 745 throw new InvalidObjectException("Illegal mappings count: " + 746 mappings); 747 748 // capacity chosen by number of mappings and desired load (if >= 0.25) 749 int capacity = (int) Math.min( 750 mappings * Math.min(1 / loadFactor, 4.0f), 751 // we have limits... 752 HashMap.MAXIMUM_CAPACITY); 753 754 // allocate the bucket array; 755 if (mappings > 0) { 756 inflateTable(capacity); 757 } else { 758 threshold = capacity; 759 } 760 761 init(); // Give subclass a chance to do its thing. 762 763 // Read the keys and values, and put the mappings in the HashMap 764 for (int i = 0; i < mappings; i++) { 765 K key = (K) s.readObject(); 766 V value = (V) s.readObject(); 767 putForCreate(key, value); 768 } 769 } 770 771 // These methods are used when serializing HashSets 772 int capacity() { return table.length; } 773 float loadFactor() { return loadFactor; } 774 }

浙公网安备 33010602011771号