java hashmap源代码_Java HashMap源代码详解

1 packagejava2.util2;2

3 importjava.io.IOException;4 importjava.io.Serializable;5 importjava.util.AbstractCollection;6 importjava.util.AbstractSet;7 importjava.util.Collection;8 importjava.util.ConcurrentModificationException;9 importjava.util.Iterator;10 importjava.util.NoSuchElementException;11 importjava.util.Set;12 /**

13 * HashMap14 *@authorwwl15 *16 *@param17 *@param18 */

19 public class HashMap extends AbstractMap implements Map,20 Cloneable, Serializable {21

22 //系统默认初始容量,必须是2的n次幂,这是出于优化考虑的

23 static final int DEFAULT_INITIAL_CAPACITY = 16;24

25 //系统默认最大容量2的30次幂1073741824

26 static final int MAXIMUM_CAPACITY = 1 << 30;27

28 //系统默认负载因子,可在构造函数中指定

29 static final float DEFAULT_LOAD_FACTOR = 0.75f;30

31 //用于存储的表,长度可以调整,且必须是2的n次幂

32 transientEntry[] table;33

34 //当前map的key-value映射数,也就是当前size

35 transient intsize;36

37 /**

38 * 表示HashMap所能容纳的key-value对极限,如果存储的size数大于了threshold,则需要扩容了39 * 阈值40 *@serial

41 */

42 intthreshold;43

44 /**

45 * 哈希表的负载因子46 * loadFactor是负载因子,增大值时可以减少Hash表(也就是Entry数组)所占用的内存空间,47 * 但会增加查询数据时时间的开销,而查询是最频繁的操作,减小值时会提高数据查询的性能, 但是会增大Hash表所占用的内存空间,所以一般是默认的0.7548 *49 *@serial

50 */

51 final floatloadFactor;52

53 /**

54 * 用于确保使用迭代器的时候,HashMap并未进行更改55 */

56 transient volatile intmodCount;57

58 /**

59 * 构造一个带指定初始容量和加载因子的空 HashMap60 *61 *@paraminitialCapacity62 * 初始容量63 *@paramloadFactor64 * 加载因子65 *@throwsIllegalArgumentException66 * if the initial capacity is negative or the load factor is67 * nonpositive68 */

69 public HashMap(int initialCapacity, floatloadFactor) {70 //如果指定初始容量小于0,抛错

71 if (initialCapacity < 0)72 throw new IllegalArgumentException("Illegal initial capacity: "

73 +initialCapacity);74 //如果初始容量大于系统默认最大容量,则初始容量为最大容量

75 if (initialCapacity >MAXIMUM_CAPACITY)76 initialCapacity =MAXIMUM_CAPACITY;77 //如果loadFactor小于0,或loadFactor是NaN,则抛错

78 if (loadFactor <= 0 ||Float.isNaN(loadFactor))79 throw new IllegalArgumentException("Illegal load factor: "

80 +loadFactor);81 //寻找一个2的k次幂capacity恰好大于initialCapacity

82 int capacity = 1;83 while (capacity

85 capacity <<= 1;86

87 this.loadFactor =loadFactor;88 threshold = (int) (capacity * loadFactor);//设置容量极限89 //创建一个capacity长度的数组用于保存数据

90 table = newEntry[capacity];91 init();92 }93

94 /**

95 * 构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap96 *97 *@paraminitialCapacity98 * 初始容量99 *@throwsIllegalArgumentException100 * if the initial capacity is negative.101 */

102 public HashMap(intinitialCapacity) {103 this(initialCapacity, DEFAULT_LOAD_FACTOR);104 }105

106 /**

107 * 构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap108 */

109 publicHashMap() {110 this.loadFactor =DEFAULT_LOAD_FACTOR;111 threshold = (int) (DEFAULT_INITIAL_CAPACITY *DEFAULT_LOAD_FACTOR);112 table = newEntry[DEFAULT_INITIAL_CAPACITY];113 init();114 }115

116 /**

117 * 构造一个映射关系与指定 Map 相同的新 HashMap118 *119 */

120 public HashMap(Map extends K, ? extends V>m) {121 this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,122 DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);123 putAllForCreate(m);124 }125 /**

126 * 初始化127 */

128 voidinit() {129 }130

131 /**

132 * HashMap的哈希函数133 * 预处理hash值,避免较差的离散hash序列134 *@paramh135 *@return

136 */

137 static int hash(inth) {138 h ^= (h >>> 20) ^ (h >>> 12);139 return h ^ (h >>> 7) ^ (h >>> 4);140 }141

142 /**

143 * 返回对应hash值得索引144 * 根据key的hash值获取哈希地址145 *@paramh146 *@paramlength147 *@return

148 */

149 static int indexFor(int h, intlength) {150 //由于length是2的n次幂,所以h & (length-1)相当于h % length

151 return h & (length - 1);152 }153

154 /**

155 * 返回当前map的key-value映射数,也就是当前size156 */

157 public intsize() {158 returnsize;159 }160 /**

161 * 该HashMap是否是空的,如果size为0,则为空162 */

163 public booleanisEmpty() {164 return size == 0;165 }166 /**

167 * 返回指定键所映射的值;如果对于该键来说,此映射不包含任何映射关系,则返回 null168 * 先根据输入的key计算hash值,得出index,找到对应数组节点,在节点内的链表结构中遍历寻找所求数据169 */

170 publicV get(Object key) {171 if (key == null)172 returngetForNullKey();173 int hash =hash(key.hashCode());174 //得到对应的hash值的桶,如果这个桶不是,就通过next获取下一个桶

175 for (Entry e = table[indexFor(hash, table.length)]; e != null; e =e.next) {176 Object k;177 if (e.hash == hash && ((k = e.key) == key ||key.equals(k)))178 returne.value;179 }180 return null;181 }182 /**

183 * 如果要得到key为null的值,则通过这个获取184 *@return

185 */

186 privateV getForNullKey() {187 for (Entry e = table[0]; e != null; e =e.next) {188 if (e.key == null)189 returne.value;190 }191 return null;192 }193

194 /**

195 * 如果此映射包含对于指定键的映射关系,则返回 true196 */

197 public booleancontainsKey(Object key) {198 return getEntry(key) != null;199 }200

201 /**

202 * 通过key获取一个value203 */

204 final EntrygetEntry(Object key) {205 //如果key为null,则hash为0,否则用hash函数预处理

206 int hash = (key == null) ? 0: hash(key.hashCode());207 //先得到对应的hash值的桶,再比较key值如果这个桶不是,就通过next获取下一个桶

208 for (Entry e = table[indexFor(hash, table.length)]; e != null; e =e.next) {209 Object k;210 if (e.hash ==hash211 && ((k = e.key) == key || (key != null &&key.equals(k))))212 returne;213 }214 return null;215 }216

217 /**

218 * 存放K-V219 * 采用链地址法220 * 哈希值[0,m-1],先计算hash根据哈希存放到对应hash值桶中,可以存放多个相同的hash221 * 在此映射中关联指定值与指定键。如果该映射以前包含了一个该键的映射关系,则旧值被替换222 */

223 publicV put(K key, V value) {224 if (key == null)225 returnputForNullKey(value);226 int hash =hash(key.hashCode());227 int i =indexFor(hash, table.length);228 //先得到对应的hash值的格子,判断该hash值的格子中下是否已经存储数据,若不为空则已存在,则新数据需要通过next获取下一个桶

229 for (Entry e = table[i]; e != null; e =e.next) {230 Object k;231 //如果hash相同并且key相同 ,则旧值被替换

232 if (e.hash == hash && ((k = e.key) == key ||key.equals(k))) {233 V oldValue =e.value;234 e.value =value;235 e.recordAccess(this);236 returnoldValue;237 }238 }239

240 modCount++;241 addEntry(hash, key, value, i);242 return null;243 }244

245 /**

246 * 当key为空时进行存放247 * 物理存储采用链表结构248 */

249 privateV putForNullKey(V value) {250 for (Entry e = table[0]; e != null; e =e.next) {251 if (e.key == null) {252 V oldValue =e.value;253 e.value =value;254 e.recordAccess(this);255 returnoldValue;256 }257 }258 modCount++;259 addEntry(0, null, value, 0);260 return null;261 }262

263 /**

264 * 检查当前已创建的桶是存在265 */

266 private voidputForCreate(K key, V value) {267 int hash = (key == null) ? 0: hash(key.hashCode());268 int i =indexFor(hash, table.length);269

270 //遍历所有桶

271 for (Entry e = table[i]; e != null; e =e.next) {272 Object k;273 //如果有hash相同,且key相同,那么则不需要创建新的桶,退出

274 if (e.hash ==hash275 && ((k = e.key) == key || (key != null &&key.equals(k)))) {276 e.value =value;277 return;278 }279 }280 //否则,不存在hash值桶需要创建新的桶

281 createEntry(hash, key, value, i);282 }283 /**

284 * 根据Map创建所有对应的桶285 *@paramm286 */

287 private void putAllForCreate(Map extends K, ? extends V>m) {288 for (Iterator extends Map.Entry extends K, ? extends V>> i =m289 .entrySet().iterator(); i.hasNext();) {290 Map.Entry extends K, ? extends V> e =i.next();291 putForCreate(e.getKey(), e.getValue());292 }293 }294

295 /**

296 * 根据新的容量来resize这个HashMap297 *@paramnewCapacity298 */

299 void resize(intnewCapacity) {300 Entry[] oldTable =table;301 int oldCapacity =oldTable.length;302 if (oldCapacity ==MAXIMUM_CAPACITY) {303 threshold =Integer.MAX_VALUE;304 return;305 }306 //根据新的容量新建一个table

307 Entry[] newTable = newEntry[newCapacity];308 //将table转换成newTable

309 transfer(newTable);310 //将table设置newTable

311 table =newTable;312 //设置阈值

313 threshold = (int) (newCapacity *loadFactor);314 }315

316 /**

317 * 动态扩展后,将所有格子里的桶都放到新的table中318 */

319 voidtransfer(Entry[] newTable) {320 Entry[] src =table;321 int newCapacity =newTable.length;322 for (int j = 0; j < src.length; j++) {323 Entry e =src[j];324 if (e != null) {325 src[j] = null;326 do{327 Entry next =e.next;328 int i =indexFor(e.hash, newCapacity);329 e.next =newTable[i];330 newTable[i] =e;331 e =next;332 } while (e != null);333 }334 }335 }336

337 /**

338 * 将另一个Map对象copy到当前对象339 * 将指定映射的所有映射关系复制到此映射中,这些映射关系将替换此映射目前针对指定映射中所有键的所有映射关系340 */

341 public void putAll(Map extends K, ? extends V>m) {342 //需要复制多少个映射关系

343 int numKeysToBeAdded =m.size();344 if (numKeysToBeAdded == 0)345 return;346

347 //如果要复制的映射关系比阈值还要多

348 if (numKeysToBeAdded >threshold) {349 //重新计算新的容量先resize

350 int targetCapacity = (int) (numKeysToBeAdded / loadFactor + 1);351 if (targetCapacity >MAXIMUM_CAPACITY)352 targetCapacity =MAXIMUM_CAPACITY;353 int newCapacity =table.length;354 while (newCapacity table.length)357 resize(newCapacity);358 }359 //迭代将key-value映射放进该HashMap

360 for (Iterator extends Map.Entry extends K, ? extends V>> i =m361 .entrySet().iterator(); i.hasNext();) {362 Map.Entry extends K, ? extends V> e =i.next();363 put(e.getKey(), e.getValue());364 }365 }366

367 /**

368 * 从此映射中移除指定键的映射关系(如果存在)369 */

370 publicV remove(Object key) {371 Entry e =removeEntryForKey(key);372 return (e == null ? null: e.value);373 }374

375 /**

376 * 根据key删除桶,并返回对应value377 */

378 final EntryremoveEntryForKey(Object key) {379 int hash = (key == null) ? 0: hash(key.hashCode());380 int i =indexFor(hash, table.length);381 //找到对应的格子

382 Entry prev =table[i];383 Entry e =prev;384 //遍历所有桶

385 while (e != null) {386 Entry next =e.next;387 Object k;388 //如果找到对应的桶

389 if (e.hash ==hash390 && ((k = e.key) == key || (key != null &&key.equals(k)))) {391 modCount++;392 size--;393 //如果第一个就是要删的桶

394 if (prev ==e)395 //则table[i]等于下一个桶

396 table[i] =next;397 else

398 //否则上一个桶的下一个等于下一个桶

399 prev.next =next;400 e.recordRemoval(this);401 returne;402 }403 prev =e;404 e =next;405 }406

407 returne;408 }409

410 /**

411 * 根据桶来删除map里的值412 */

413 final EntryremoveMapping(Object o) {414 //如果o不是Map.Entry的实例,则退出返回null

415 if (!(o instanceofMap.Entry))416 return null;417 //将o转成Map.Entry

418 Map.Entry entry = (Map.Entry) o;419 Object key =entry.getKey();420 int hash = (key == null) ? 0: hash(key.hashCode());421 int i =indexFor(hash, table.length);422 Entry prev =table[i];423 Entry e =prev;424

425 while (e != null) {426 Entry next =e.next;427 if (e.hash == hash &&e.equals(entry)) {428 modCount++;429 size--;430 if (prev ==e)431 table[i] =next;432 else

433 prev.next =next;434 e.recordRemoval(this);435 returne;436 }437 prev =e;438 e =next;439 }440

441 returne;442 }443

444 /**

445 * 从此映射中移除所有映射关系。此调用返回后,映射将为空446 */

447 public voidclear() {448 modCount++;449 Entry[] tab =table;450 //遍历table中的所有格子,然偶后设为nul

451 for (int i = 0; i < tab.length; i++)452 tab[i] = null;453 size = 0;454 }455

456 /**

457 * 如果此映射将一个或多个键映射到指定值,则返回 true458 */

459 public booleancontainsValue(Object value) {460 //如果value为空,则返回containsNullValue函数的返回值

461 if (value == null)462 returncontainsNullValue();463

464 Entry[] tab =table;465 //遍历table所有格子(链表)

466 for (int i = 0; i < tab.length; i++)467 //遍历链表中的每个桶

468 for (Entry e = tab[i]; e != null; e =e.next)469 //如果值相同,则返回true

470 if(value.equals(e.value))471 return true;472 return false;473 }474

475 /**

476 * 对value为null的处理477 */

478 private booleancontainsNullValue() {479 Entry[] tab =table;480 for (int i = 0; i < tab.length; i++)481 for (Entry e = tab[i]; e != null; e =e.next)482 if (e.value == null)483 return true;484 return false;485 }486

487 /**

488 * 返回此 HashMap 实例的浅表副本:并不复制键和值本身489 */

490 publicObject clone() {491 HashMap result = null;492 try{493 result = (HashMap) super.clone();494 } catch(CloneNotSupportedException e) {495 //assert false;

496 }497 result.table = newEntry[table.length];498 result.entrySet = null;499 result.modCount = 0;500 result.size = 0;501 result.init();502 result.putAllForCreate(this);503

504 returnresult;505 }506 /**

507 * 内置class输入对象,也就是桶508 *@authorwwl509 *510 *@param511 *@param512 */

513 static class Entry implements Map.Entry{514 finalK key;515 V value;516 Entrynext;517 final inthash;518

519 /**

520 * 构造函数521 */

522 Entry(int h, K k, V v, Entryn) {523 value =v;524 next =n;525 key =k;526 hash =h;527 }528 /**

529 * 返回key530 */

531 public finalK getKey() {532 returnkey;533 }534 /**

535 * 返回value536 */

537 public finalV getValue() {538 returnvalue;539 }540 /**

541 * 设置value542 */

543 public finalV setValue(V newValue) {544 V oldValue =value;545 value =newValue;546 returnoldValue;547 }548 /**

549 * 是否相同,比对的是key与value550 */

551 public final booleanequals(Object o) {552 //如果o不是Map.Entry的实例,那么肯定不相同了

553 if (!(o instanceofMap.Entry))554 return false;555 //将o转成Map.Entry

556 Map.Entry e =(Map.Entry) o;557 //得到key和value对比是否相同,相同则为true

558 Object k1 =getKey();559 Object k2 =e.getKey();560 if (k1 == k2 || (k1 != null &&k1.equals(k2))) {561 Object v1 =getValue();562 Object v2 =e.getValue();563 if (v1 == v2 || (v1 != null &&v1.equals(v2)))564 return true;565 }566 return false;567 }568

569 public final inthashCode() {570 return (key == null ? 0: key.hashCode())571 ^ (value == null ? 0: value.hashCode());572 }573

574 public finalString toString() {575 return getKey() + "=" +getValue();576 }577

578 /**

579 * 使用该方法证明该key已经在该map中580 */

581 void recordAccess(HashMapm) {582 }583

584 /**

585 * 该方法记录该key已经被移除了586 */

587 void recordRemoval(HashMapm) {588 }589 }590

591 /**

592 * 添加一个新的桶来保存该key和value593 */

594 void addEntry(int hash, K key, V value, intbucketIndex) {595 Entry e =table[bucketIndex];596 table[bucketIndex] = new Entry(hash, key, value, e);597 if (size++ >=threshold)598 resize(2 *table.length);599 }600

601 /**

602 * 新建一个桶,该方法不需要判断是否超过阈值603 */

604 void createEntry(int hash, K key, V value, intbucketIndex) {605 Entry e =table[bucketIndex];606 table[bucketIndex] = new Entry(hash, key, value, e);607 size++;608 }609 /**

610 * 内部class HashIterator迭代器611 *@authorwwl612 *613 *@param614 */

615 private abstract class HashIterator implements Iterator{616 Entry next; //下一个桶

617 int expectedModCount; //保护HashMap没有变更

618 int index; //当前的索引

619 Entry current; //当前的桶

620

621 HashIterator() {622 //保存modCount,因为如果HashMap进行了任何操作modCount都会增加,所以如果发现modCount变化了,就可以抛出失败

623 expectedModCount =modCount;624 if (size > 0) { //进入第一个桶

625 Entry[] t =table;626 while (index < t.length && (next = t[index++]) == null)627 ;628 }629 }630 /**

631 * 判断有没有下一个桶632 */

633 @Override634 public final booleanhasNext() {635 return next != null;636 }637 /**

638 * 获取下一个桶639 *@return

640 */

641 final EntrynextEntry() {642 if (modCount !=expectedModCount)643 throw newConcurrentModificationException();644 Entry e =next;645 //如果next为空,抛出失败

646 if (e == null)647 throw newNoSuchElementException();648 //如果next.next为空,将next定义为下一个格子中的桶,否则为该格子的下一个桶

649 if ((next = e.next) == null) {650 Entry[] t =table;651 while (index < t.length && (next = t[index++]) == null)652 ;653 }654 current =e;655 returne;656 }657 /**

658 * 删除659 */

660 @Override661 public voidremove() {662 //如果当前为空,抛出

663 if (current == null)664 throw newIllegalStateException();665 //modCount变化了,抛出失败

666 if (modCount !=expectedModCount)667 throw newConcurrentModificationException();668 //获得当前的key

669 Object k =current.key;670 //设置current为null

671 current = null;672 //删除掉对应key的元素

673 HashMap.this.removeEntryForKey(k);674 //重置expectedModCount

675 expectedModCount =modCount;676 }677

678 }679 /**

680 * 内部class ValueIterator迭代器,重写next方法681 *@authorwwl682 *683 */

684 private final class ValueIterator extends HashIterator{685 @Override686 publicV next() {687 returnnextEntry().value;688 }689 }690 /**

691 * 内部class KeyIterator迭代器,重写next方法692 *@authorwwl693 *694 */

695 private final class KeyIterator extends HashIterator{696 publicK next() {697 returnnextEntry().getKey();698 }699 }700 /**

701 * 内部class EntryIterator迭代器,重写next方法702 *@authorwwl703 *704 */

705 private final class EntryIterator extends HashIterator>{706 public Map.Entrynext() {707 returnnextEntry();708 }709 }710

711 /**

712 * 定义对应的 iterator() 方法713 *@return

714 */

715 IteratornewKeyIterator() {716 return newKeyIterator();717 }718 /**

719 * 定义对应的 iterator() 方法720 *@return

721 */

722 IteratornewValueIterator() {723 return newValueIterator();724 }725 /**

726 * 定义对应的 iterator() 方法727 *@return

728 */

729 Iterator>newEntryIterator() {730 return newEntryIterator();731 }732

733 //Views

734

735 private transient Set> entrySet = null;736

737 /**

738 * 返回此映射中所包含的键的 Set 视图739 */

740 public SetkeySet() {741 Set ks =keySet;742 return (ks != null ? ks : (keySet = newKeySet()));743 }744

745 /**

746 * 内部类KeySet对象747 *@authorwwl748 *749 */

750 private final class KeySet extends AbstractSet{751 public Iteratoriterator() {752 returnnewKeyIterator();753 }754

755 public intsize() {756 returnsize;757 }758

759 public booleancontains(Object o) {760 returncontainsKey(o);761 }762

763 public booleanremove(Object o) {764 return HashMap.this.removeEntryForKey(o) != null;765 }766

767 public voidclear() {768 HashMap.this.clear();769 }770 }771

772 /**

773 * 返回此映射所包含的值的 Collection 视图774 */

775 public Collectionvalues() {776 Collection vs =values;777 return (vs != null ? vs : (values = newValues()));778 }779

780 /**

781 * 内部类Values782 *783 *@authorwwl784 *785 */

786 private final class Values extends AbstractCollection{787 public Iteratoriterator() {788 returnnewValueIterator();789 }790

791 public intsize() {792 returnsize;793 }794

795 public booleancontains(Object o) {796 returncontainsValue(o);797 }798

799 public voidclear() {800 HashMap.this.clear();801 }802 }803

804 /**

805 * 返回此映射所包含的映射关系的 Set 视图806 */

807 public Set>entrySet() {808 returnentrySet0();809 }810

811 private Set>entrySet0() {812 Set> es =entrySet;813 return es != null ? es : (entrySet = newEntrySet());814 }815

816 /**

817 * 内部类EntrySet对象818 *819 *@authorwwl820 *821 */

822 private final class EntrySet extends AbstractSet>{823 public Iterator>iterator() {824 returnnewEntryIterator();825 }826

827 public booleancontains(Object o) {828 if (!(o instanceofMap.Entry))829 return false;830 Map.Entry e = (Map.Entry) o;831 Entry candidate =getEntry(e.getKey());832 return candidate != null &&candidate.equals(e);833 }834

835 public booleanremove(Object o) {836 return removeMapping(o) != null;837 }838

839 public intsize() {840 returnsize;841 }842

843 public voidclear() {844 HashMap.this.clear();845 }846 }847

848 /**

849 * 序列化方法850 */

851 private void writeObject(java.io.ObjectOutputStream s) throwsIOException {852 Iterator> i = (size > 0) ?entrySet0().iterator()853 : null;854

855 s.defaultWriteObject();856

857 s.writeInt(table.length);858

859 s.writeInt(size);860

861 if (i != null) {862 while(i.hasNext()) {863 Map.Entry e =i.next();864 s.writeObject(e.getKey());865 s.writeObject(e.getValue());866 }867 }868 }869

870 private static final long serialVersionUID = 362498820763181265L;871

872 /**

873 * 通过序列读取对象874 */

875 private void readObject(java.io.ObjectInputStream s) throwsIOException,876 ClassNotFoundException {877 s.defaultReadObject();878

879 int numBuckets =s.readInt();880 table = newEntry[numBuckets];881

882 init();883

884 int size =s.readInt();885

886 for (int i = 0; i < size; i++) {887 K key =(K) s.readObject();888 V value =(V) s.readObject();889 putForCreate(key, value);890 }891 }892

893 intcapacity() {894 returntable.length;895 }896

897 floatloadFactor() {898 returnloadFactor;899 }900 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值