• java数据结构HashMap
  1. /**
  2. * <html>
  3. * <body>
  4. * <P> Copyright JasonInternational</p>
  5. * <p> All rights reserved.</p>
  6. * <p> Created on 2018年6月27日 下午7:28:09</p>
  7. * <p> Created by Jason </p>
  8. * </body>
  9. * </html>
  10. */
  11. package cn.ucaner.sourceanalysis.map;
  12.  
  13. import java.io.IOException;
  14. import java.io.Serializable;
  15. import java.util.AbstractCollection;
  16. import java.util.AbstractMap;
  17. import java.util.AbstractSet;
  18. import java.util.ConcurrentModificationException;
  19. import java.util.Iterator;
  20. import java.util.Map;
  21. import java.util.NoSuchElementException;
  22. import java.util.Set;
  23.  
  24. /**
  25. * @Package:cn.ucaner.sourceanalysis
  26. * @ClassName:HashMap
  27. * @Description: <p>HashMap 源码分析 {@link https://www.cnblogs.com/peizhe123/p/5790252.html}</p>
  28. * <core>
  29. * HashMap是基于哈希表实现的,每一个元素都是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阈值)时,同样会自动增长.
  30. * HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap.
  31. * HashMap实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆.
  32. * </core>
  33. * @Author: - Jason
  34. * @CreatTime:2018年6月27日 下午7:28:09
  35. * @Modify By:
  36. * @ModifyTime: 2018年6月27日
  37. * @Modify marker:
  38. * @version V1.0
  39. */
  40.  
  41. /*
  42. 1.哈希数组,数组的每个元素都是一个单链表的头节点,链表是用来解决冲突的,如果不同的key映射到了数组的同一位置处,就将其放入单链表中。
  43. 2.HashMap共有四个构造方法(构造方法中提到了两个很重要的参数:初始容量和加载因子)
  44. 两个参数是影响HashMap性能的重要参数,其中容量表示哈希表中槽的数量(即哈希数组的长度),
  45. 初始容量是创建哈希表时的容量(从构造函数中可以看出,如果不指明,则默认为16),
  46. 加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度,当哈希表中的条目数超出了加载因子与当前容量的乘积时,
  47. 则要对该哈希表进行 resize 操作(即扩容).
  48.  
  49. 如果加载因子越大,对空间的利用更充分,但是查找效率会降低(链表长度会越来越长)
  50. 如果加载因子太小,那么表中的数据将过于稀疏(很多空间还没用,就开始扩容了)
  51. 如果我们在构造方法中不指定,则系统默认加载因子为0.75,这是一个比较理想的值,一般情况下我们是无需修改的
  52. 3.HashMap中key和value都允许为null
  53. 4.如果key为null,则直接从哈希表的第一个位置table[0]对应的链表上查找.记住,key为null的键值对永远都放在以table[0]为头结点的链表中,当然不一定是存放在头结点table[0]中
  54. 5.如果key不为null,则先求的key的hash值,根据hash值找到在table中的索引,在该索引对应的单链表中查找是否有键值对的key与目标key相等,有就返回对应的value,没有则返回null
  55. 6.扩容是一个相当耗时的操作,因为它需要重新计算这些元素在新的数组中的位置并进行复制处理。因此,我们在用HashMap的时,最好能提前预估下HashMap中元素的个数,这样有助于提高HashMap的性能
  56. 7.注意containsKey方法和containsValue方法。前者直接可以通过key的哈希值将搜索范围定位到指定索引对应的链表[桶],而后者要对哈希数组的每个链表进行搜索。
  57. 8.h & (length-1) [16大小的数据table[]] hash & (legth-1)
  58. 我们分析下为什么哈希表的容量一定要是2的整数次幂。
  59. 首先,length为2的整数次幂的话,h&(length-1)就相当于对length取模,这样便保证了散列的均匀,同时也提升了效率;
  60. 其次,length为2的整数次幂的话,为偶数,这样length-1为奇数,奇数的最后一位是1,这样便保证了h&(length-1)的最后一位可能为0,也可能为1(这取决于h的值),
  61. 即与后的结果可能为偶数,也可能为奇数,这样便可以保证散列的均匀性,而如果length为奇数的话,很明显length-1为偶数,
  62. 它的最后一位是0,这样h&(length-1)的最后一位肯定为0,即只能为偶数,这样任何hash值都只会被散列到数组的偶数下标位置上,
  63. 这便浪费了近一半的空间,因此,length取2的整数次幂,是为了使不同hash值发生碰撞的概率较小,
  64. 这样就能使元素在哈希表中均匀地散列。
  65.  
  66. */
  67. public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
  68.  
  69. private static final long serialVersionUID = -6879885499611748731L;
  70.  
  71. /**
  72. * 默认的初始容量(容量为HashMap中槽的数目)是16 .且实际容量必须是2的整数次幂
  73. */
  74. static final int DEFAULT_INITIAL_CAPACITY = 16;
  75.  
  76. /**
  77. * 最大容量(必须是2的幂且小于2的30次方,传入容量过大将被这个值替换) --> 1073741824
  78. */
  79. static final int MAXIMUM_CAPACITY = 1 << 30;
  80.  
  81. /**
  82. * 默认加载因子为0.75
  83. */
  84. static final float DEFAULT_LOAD_FACTOR = 0.75f;
  85.  
  86. /**
  87. * 存储数据的Entry数组,长度是2的幂
  88. * HashMap采用链表法解决冲突,每一个Entry本质上是一个单向链表
  89. */
  90. transient Entry[] table;
  91.  
  92. /**
  93. * HashMap的底层数组中已用槽的数量
  94. */
  95. transient int size;
  96.  
  97. /**
  98. * HashMap的阈值,用于判断是否需要调整HashMap的容量(threshold = 容量*加载因子)
  99. */
  100. int threshold;
  101.  
  102. /**
  103. * 加载因子实际大小 ? init 初始化 有点意思
  104. */
  105. final float loadFactor;
  106.  
  107. /**
  108. * HashMap被改变的次数
  109. */
  110. transient volatile int modCount;
  111.  
  112. /**
  113. * HashMap. Constructe
  114. * @param initialCapacity 容量大小
  115. * @param loadFactor 加载因子
  116. */
  117. public HashMap(int initialCapacity, float loadFactor) {
  118. if (initialCapacity < 0)
  119. throw new IllegalArgumentException("[Java-Core-Advanced]Illegal initial capacity: " + initialCapacity);
  120. /**
  121. * HashMap的最大容量只能是MAXIMUM_CAPACITY > 赋值回去
  122. */
  123. if (initialCapacity > MAXIMUM_CAPACITY) {
  124. initialCapacity = MAXIMUM_CAPACITY;
  125. }
  126.  
  127. /**
  128. * 加载因此不能小于0 . - 0.75
  129. */
  130. if (loadFactor <= 0 || Float.isNaN(loadFactor))
  131. throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
  132. /**
  133. * 找出"大于initialCapacity"的最小的2的幂
  134. */
  135. int capacity = 1;
  136. while (capacity < initialCapacity) { //while 循环每次左移动2位 capacity^(n+1)
  137. capacity <<= 1;
  138. }
  139. /**
  140. * 设置加载因子
  141. */
  142. this.loadFactor = loadFactor;
  143.  
  144. /**
  145. * 设置"HashMap阈值"当HashMap中存储数据的数量达到threshold时,就需要将HashMap的容量加倍
  146. * HashMap的阈值 - 阈值调整 by Jason
  147. */
  148. threshold = (int)(capacity * loadFactor); // *0.75
  149.  
  150. /**
  151. * 创建Entry数组,用来保存数据
  152. */
  153. table = new Entry[capacity]; //k,v 数组
  154.  
  155. /**
  156. * 初始化
  157. */
  158. // init();
  159. }
  160.  
  161. /**
  162. * HashMap. 指定"容量大小"的构造函数
  163. * @param initialCapacity
  164. */
  165. public HashMap(int initialCapacity) {
  166. this(initialCapacity, DEFAULT_LOAD_FACTOR); //DEFAULT_LOAD_FACTOR 0.75f 扩容因子
  167. }
  168.  
  169. /**
  170. * HashMap. 默认构造函数。
  171. */
  172. public HashMap() {
  173. /**
  174. * 设置"加载因子"为默认加载因子0.75
  175. */
  176. this.loadFactor = DEFAULT_LOAD_FACTOR;
  177. /**
  178. * 设置"HashMap阈值",当HashMap中存储数据的数量达到threshold时,就需要将HashMap的容量加倍。
  179. */
  180. threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); //0.75 阈值
  181. /**
  182. * 创建Entry数组,用来保存数据
  183. */
  184. table = new Entry[DEFAULT_INITIAL_CAPACITY];
  185. //init();
  186. }
  187.  
  188. /**
  189. * HashMap. 包含"子Map"的构造函数
  190. * @param m
  191. */
  192. public HashMap(Map<? extends K, ? extends V> m) {
  193. //[(size/0.75)+1,16],0.75 (a >= b) ? a : b 返回最大的那个.
  194. this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
  195. putAllForCreate(m);// 将m中的全部元素逐个添加到HashMap中
  196. }
  197.  
  198. /**
  199. * @Description: 求hash值的方法,重新计算hash值
  200. * @param h
  201. * @return int
  202. * @Autor: Jason
  203. * @Date: 2018年6月27日
  204. */
  205. static int hash(int h) {
  206. h ^= (h >>> 20) ^ (h >>> 12);
  207. return h ^ (h >>> 7) ^ (h >>> 4);
  208. }
  209.  
  210. /**
  211. * @Description: 返回h在数组中的索引值,这里用&代替取模,旨在提升效率 .h & (length-1)保证返回值的小于lengt
  212. * @param h
  213. * @param length
  214. * @return int
  215. * @Autor: Jason
  216. * @Date: 2018年6月27日
  217. */
  218. static int indexFor(int h, int length) {
  219. return h & (length-1); //与逻辑 10001 & 1000 = 1 000 有点类似子网掩码 by Jason
  220. }
  221.  
  222. /**
  223. * 返回大小Size
  224. */
  225. public int size() {
  226. return size;
  227. }
  228.  
  229. /**
  230. * 是否为空
  231. */
  232. public boolean isEmpty() {
  233. return size == 0;
  234. }
  235.  
  236. /**
  237. * 获取key对应的value
  238. */
  239. public V get(Object key) {
  240. if (key == null) {
  241. return getForNullKey();
  242. }
  243. /**
  244. * 获取key的hash值
  245. */
  246. int hash = hash(key.hashCode());
  247. // 在"该hash值对应的链表"上查找"键值等于key"的元素
  248. for (Entry<K,V> e = table[indexFor(hash, table.length)];
  249. e != null;
  250. e = e.next) {
  251. Object k;
  252. /**
  253. * 判断key是否相同
  254. */
  255. if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
  256. return e.value;
  257. }
  258. /**
  259. * 没找到则返回null
  260. */
  261. return null;
  262. }
  263.  
  264. /**
  265. * @Description: 获取"key为null"的元素的值
  266. * HashMap将"key为null"的元素存储在table[0]位置,但不一定是该链表的第一个位置!
  267. * @return V
  268. * @Autor: Jason
  269. * @Date: 2018年6月27日
  270. */
  271. private V getForNullKey() {
  272. for (Entry<K,V> e = table[0]; e != null; e = e.next) {
  273. if (e.key == null)
  274. return e.value;
  275. }
  276. return null;
  277. }
  278.  
  279. /**
  280. * HashMap是否包含key
  281. */
  282. public boolean containsKey(Object key) {
  283. return getEntry(key) != null;
  284. }
  285.  
  286. /**
  287. * @Description: 返回"键为key"的键值对
  288. * @param key
  289. * @return Entry<K,V>
  290. * @Autor: Jason
  291. * @Date: 2018年6月27日
  292. */
  293. final Entry<K,V> getEntry(Object key) {
  294. /**
  295. * 获取哈希值
  296. * HashMap将"key为null"的元素存储在table[0]位置,"key不为null"的则调用hash()计算哈希值
  297. */
  298. int hash = (key == null) ? 0 : hash(key.hashCode());
  299. /**
  300. * 在"该hash值对应的链表"上查找"键值等于key"的元素
  301. */
  302. for (Entry<K,V> e = table[indexFor(hash, table.length)];
  303. e != null;
  304. e = e.next) {
  305. Object k;
  306. if (e.hash == hash &&
  307. ((k = e.key) == key || (key != null && key.equals(k))))
  308. return e;
  309. }
  310. return null;
  311. }
  312.  
  313. /**
  314. * 将"key-value"添加到HashMap中 --- HashMap Core logic
  315. */
  316. public V put(K key, V value) {
  317. /**
  318. * 若"key为null",则将该键值对添加到table[0]中
  319. */
  320. if (key == null) {
  321. return putForNullKey(value);
  322. }
  323.  
  324. /**
  325. * 若"key不为null",则计算该key的哈希值,然后将其添加到该哈希值对应的链表中。
  326. */
  327. int hash = hash(key.hashCode());
  328. int i = indexFor(hash, table.length);
  329. for (Entry<K,V> e = table[i]; e != null; e = e.next) {
  330. Object k;
  331. /**
  332. * 若"该key"对应的键值对已经存在,则用新的value取代旧的value。然后退出!
  333. */
  334. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
  335. V oldValue = e.value;
  336. e.value = value;
  337. e.recordAccess(this);
  338. return oldValue;
  339. }
  340. }
  341.  
  342. /**
  343. * 若"该key"对应的键值对不存在,则将"key-value"添加到table中
  344. */
  345. modCount++;
  346. /**
  347. * 将key-value添加到table[i]处
  348. */
  349. addEntry(hash, key, value, i);
  350. return null;
  351. }
  352.  
  353. /**
  354. * @Description: putForNullKey()的作用是将"key为null"键值对添加到table[0]位置
  355. * @param value
  356. * @return V
  357. * @Autor: Jason
  358. * @Date: 2018年6月27日
  359. */
  360. private V putForNullKey(V value) {
  361. for (Entry<K,V> e = table[0]; e != null; e = e.next) {
  362. if (e.key == null) {
  363. V oldValue = e.value;
  364. e.value = value;
  365. e.recordAccess(this);
  366. return oldValue;
  367. }
  368. }
  369. /**
  370. * 如果没有存在key为null的键值对,则到table[0]处!
  371. */
  372. modCount++;
  373. addEntry(0, null, value, 0);
  374. return null;
  375. }
  376.  
  377. /**
  378. * @Description: 创建HashMap对应的"添加方法"它和put()不同。
  379. * putForCreate()是内部方法,它被构造函数等调用,用来创建HashMap 而put()是对外提供的往HashMap中添加元素的方法。
  380. * @param key
  381. * @param value void
  382. * @Autor: Jason
  383. * @Date: 2018年6月27日
  384. */
  385. private void putForCreate(K key, V value) {
  386. int hash = (key == null) ? 0 : hash(key.hashCode());
  387. int i = indexFor(hash, table.length);
  388.  
  389. /**
  390. * 若该HashMap表中存在"键值等于key"的元素,则替换该元素的value值
  391. */
  392. for (Entry<K,V> e = table[i]; e != null; e = e.next) {
  393. Object k;
  394. if (e.hash == hash &&
  395. ((k = e.key) == key || (key != null && key.equals(k)))) {
  396. e.value = value;
  397. return;
  398. }
  399. }
  400. // 若该HashMap表中不存在"键值等于key"的元素,则将该key-value添加到HashMap中
  401. createEntry(hash, key, value, i);
  402. }
  403.  
  404. /**
  405. * @Description: 将"m"中的全部元素都添加到HashMap中,该方法被内部的构造HashMap的方法所调用。
  406. * @param m void
  407. * @Autor: Jason
  408. * @Date: 2018年6月27日
  409. */
  410. private void putAllForCreate(Map<? extends K, ? extends V> m) {
  411. // 利用迭代器将元素逐个添加到HashMap中
  412. for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
  413. Map.Entry<? extends K, ? extends V> e = i.next();
  414. putForCreate(e.getKey(), e.getValue());
  415. }
  416. }
  417.  
  418. /**
  419. * @Description: 重新调整HashMap的大小,newCapacity是调整后的容量
  420. * @param newCapacity
  421. * @Autor: Jason
  422. * @Date: 2018年6月27日
  423. */
  424. void resize(int newCapacity) {
  425. Entry[] oldTable = table;
  426. int oldCapacity = oldTable.length;
  427. //如果就容量已经达到了最大值,则不能再扩容,直接返回
  428. if (oldCapacity == MAXIMUM_CAPACITY) {
  429. threshold = Integer.MAX_VALUE;
  430. return;
  431. }
  432. /**
  433. * 新建一个HashMap,将"旧HashMap"的全部元素添加到"新HashMap"中
  434. * 然后,将"新HashMap"赋值给"旧HashMap"
  435. */
  436. Entry[] newTable = new Entry[newCapacity];
  437. transfer(newTable);
  438. table = newTable;
  439. threshold = (int)(newCapacity * loadFactor);
  440. }
  441.  
  442. /**
  443. * @Description: 将HashMap中的全部元素都添加到newTable中
  444. * @param newTable
  445. * @Autor: Jason
  446. * @Date: 2018年6月27日
  447. */
  448. void transfer(Entry[] newTable) {
  449. Entry[] src = table;
  450. int newCapacity = newTable.length;
  451. for (int j = 0; j < src.length; j++) {
  452. Entry<K,V> e = src[j];
  453. if (e != null) {
  454. src[j] = null;
  455. do {
  456. Entry<K,V> next = e.next;
  457. int i = indexFor(e.hash, newCapacity);
  458. e.next = newTable[i];
  459. newTable[i] = e;
  460. e = next;
  461. } while (e != null);
  462. }
  463. }
  464. }
  465.  
  466. /**
  467. * 将"m"的全部元素都添加到HashMap中
  468. */
  469. public void putAll(Map<? extends K, ? extends V> m) {
  470. /**
  471. * 有效性判断
  472. */
  473. int numKeysToBeAdded = m.size();
  474. if (numKeysToBeAdded == 0) {
  475. return;
  476. }
  477. /**
  478. * 计算容量是否足够,若"当前阀值容量 < 需要的容量" 则将容量*2
  479. */
  480. if (numKeysToBeAdded > threshold) {
  481. int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
  482. if (targetCapacity > MAXIMUM_CAPACITY)
  483. targetCapacity = MAXIMUM_CAPACITY;
  484. int newCapacity = table.length;
  485. while (newCapacity < targetCapacity)
  486. newCapacity <<= 1;
  487. if (newCapacity > table.length)
  488. resize(newCapacity);
  489. }
  490. /**
  491. * 通过迭代器,将"m"中的元素逐个添加到HashMap中
  492. */
  493. for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
  494. Map.Entry<? extends K, ? extends V> e = i.next();
  495. put(e.getKey(), e.getValue());
  496. }
  497. }
  498.  
  499. //
  500. /**
  501. * 删除"键为key"元素
  502. */
  503. public V remove(Object key) {
  504. Entry<K,V> e = removeEntryForKey(key);
  505. return (e == null ? null : e.value);
  506. }
  507.  
  508. /**
  509. * @Description: 删除"键为key"的元素
  510. * @param key
  511. * @return Entry<K,V>
  512. * @Autor: Jason
  513. * @Date: 2018年6月27日
  514. */
  515. final Entry<K,V> removeEntryForKey(Object key) {
  516. /**
  517. * 获取哈希值 若key为null,则哈希值为0,否则调用hash()进行计算
  518. */
  519. int hash = (key == null) ? 0 : hash(key.hashCode());
  520. int i = indexFor(hash, table.length);
  521. Entry<K,V> prev = table[i];
  522. Entry<K,V> e = prev;
  523.  
  524. /**
  525. * 删除链表中"键为key"的元素
  526. * 本质是"删除单向链表中的节点"
  527. */
  528. while (e != null) {
  529. Entry<K,V> next = e.next;
  530. Object k;
  531. if (e.hash == hash &&
  532. ((k = e.key) == key || (key != null && key.equals(k)))) {
  533. modCount++;
  534. size--;
  535. if (prev == e)
  536. table[i] = next;
  537. else
  538. prev.next = next;
  539. e.recordRemoval(this);
  540. return e;
  541. }
  542. prev = e;
  543. e = next;
  544. }
  545. return e;
  546. }
  547.  
  548. /**
  549. * @Description: 删除"键值对" k-v
  550. * @param o
  551. * @return Entry<K,V>
  552. * @Autor: Jason
  553. * @Date: 2018年6月27日
  554. */
  555. final Entry<K,V> removeMapping(Object o) {
  556. if (!(o instanceof Map.Entry)) {
  557. return null;
  558. }
  559. Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
  560. Object key = entry.getKey();
  561. int hash = (key == null) ? 0 : hash(key.hashCode());
  562. int i = indexFor(hash, table.length);
  563. Entry<K,V> prev = table[i];
  564. Entry<K,V> e = prev;
  565.  
  566. /**
  567. * 删除链表中的"键值对e"
  568. * 本质是"删除单向链表中的节点"
  569. */
  570. while (e != null) {
  571. Entry<K,V> next = e.next;
  572. if (e.hash == hash && e.equals(entry)) {
  573. modCount++;
  574. size--;
  575. if (prev == e)
  576. table[i] = next;
  577. else
  578. prev.next = next;
  579. e.recordRemoval(this);
  580. return e;
  581. }
  582. prev = e;
  583. e = next;
  584. }
  585. return e;
  586. }
  587.  
  588. /**
  589. * 清空HashMap 将所有的元素设为null
  590. */
  591. public void clear() {
  592. modCount++;
  593. Entry[] tab = table;
  594. for (int i = 0; i < tab.length; i++)
  595. tab[i] = null;
  596. size = 0;
  597. }
  598.  
  599. /**
  600. * 是否包含 "值为value"的元素
  601. */
  602. public boolean containsValue(Object value) {
  603. /**
  604. * 若"value为null",则调用containsNullValue()查找
  605. */
  606. if (value == null) {
  607. return containsNullValue();
  608. }
  609. // 若"value不为null",则查找HashMap中是否有值为value的节点。
  610. Entry[] tab = table;
  611. for (int i = 0; i < tab.length ; i++)
  612. for (Entry e = tab[i] ; e != null ; e = e.next)
  613. if (value.equals(e.value))
  614. return true;
  615. return false;
  616. }
  617.  
  618. /**
  619. * @Description: 是否包含null值
  620. * @return boolean
  621. * @Autor: Jason
  622. * @Date: 2018年6月27日
  623. */
  624. private boolean containsNullValue() {
  625. Entry[] tab = table;
  626. for (int i = 0; i < tab.length ; i++)
  627. for (Entry e = tab[i] ; e != null ; e = e.next)
  628. if (e.value == null)
  629. return true;
  630. return false;
  631. }
  632.  
  633. /**
  634. *克隆一个HashMap,并返回Object对象
  635. */
  636. public Object clone() {
  637. HashMap<K,V> result = null;
  638. try {
  639. result = (HashMap<K,V>)super.clone();
  640. } catch (CloneNotSupportedException e) {
  641. // assert false;
  642. }
  643. result.table = new Entry[table.length];
  644. result.entrySet = null;
  645. result.modCount = 0;
  646. result.size = 0;
  647. // result.init();
  648. // 调用putAllForCreate()将全部元素添加到HashMap中
  649. result.putAllForCreate(this);
  650.  
  651. return result;
  652. }
  653.  
  654. /**
  655. * @Package:cn.ucaner.sourceanalysis
  656. * @ClassName:Entry
  657. * @Description: <p> Entry是单向链表 </p>
  658. * <Core>
  659. * 它是 "HashMap链式存储法"对应的链表
  660. * 它实现了Map.Entry 接口,即实现getKey(), getValue(), setValue(V value), equals(Object o), hashCode()这些函数
  661. * </Core>
  662. * @Author: - Jason
  663. * @CreatTime:2018年6月27日 下午8:16:25
  664. * @Modify By:
  665. * @ModifyTime: 2018年6月27日
  666. * @Modify marker:
  667. * @version V1.0
  668. */
  669. static class Entry<K,V> implements Map.Entry<K,V> {
  670. final K key;
  671. V value;
  672. // 指向下一个节点
  673. Entry<K,V> next;
  674. final int hash;
  675.  
  676. // 构造函数。
  677. // 输入参数包括"哈希值(h)", "键(k)", "值(v)", "下一节点(n)"
  678. Entry(int h, K k, V v, Entry<K,V> n) {
  679. value = v;
  680. next = n;
  681. key = k;
  682. hash = h;
  683. }
  684.  
  685. public final K getKey() {
  686. return key;
  687. }
  688.  
  689. public final V getValue() {
  690. return value;
  691. }
  692.  
  693. public final V setValue(V newValue) {
  694. V oldValue = value;
  695. value = newValue;
  696. return oldValue;
  697. }
  698.  
  699. /**
  700. * 判断两个Entry是否相等
  701. * 若两个Entry的"key"和"value"都相等,则返回true, 否则,返回false
  702. */
  703. public final boolean equals(Object o) {
  704. if (!(o instanceof Map.Entry))
  705. return false;
  706. Map.Entry e = (Map.Entry)o;
  707. Object k1 = getKey();
  708. Object k2 = e.getKey();
  709. if (k1 == k2 || (k1 != null && k1.equals(k2))) {
  710. Object v1 = getValue();
  711. Object v2 = e.getValue();
  712. if (v1 == v2 || (v1 != null && v1.equals(v2)))
  713. return true;
  714. }
  715. return false;
  716. }
  717.  
  718. /**
  719. * 实现hashCode()
  720. */
  721. public final int hashCode() {
  722. return (key==null ? 0 : key.hashCode()) ^ (value==null ? 0 : value.hashCode());
  723. }
  724.  
  725. /**
  726. * toString k=v
  727. */
  728. public final String toString() {
  729. return getKey() + "=" + getValue();
  730. }
  731.  
  732. /**
  733. * @Description: 当向HashMap中添加元素时,调用recordAccess(),不做任何处理
  734. * @param m void
  735. * @Autor: Jason
  736. * @Date: 2018年6月27日
  737. */
  738. void recordAccess(HashMap<K,V> m) { }
  739. /**
  740. * @Description: 当从HashMap中删除元素时,绘调用recordRemoval() 不做任何处理
  741. * @param m void
  742. * @Autor: Jason
  743. * @Date: 2018年6月27日
  744. */
  745. void recordRemoval(HashMap<K,V> m) { }
  746. }
  747.  
  748. /**
  749. * @Description: 新增Entry,将"key-value"插入指定位置,bucketIndex:位置索引
  750. * @param hash
  751. * @param key
  752. * @param value
  753. * @param bucketIndex 位置索引
  754. * @Autor: Jason
  755. * @Date: 2018年6月27日
  756. */
  757. void addEntry(int hash, K key, V value, int bucketIndex) {
  758. //
  759. /**
  760. * 保存"bucketIndex"位置的值到"e"中
  761. */
  762. Entry<K,V> e = table[bucketIndex];
  763. /**
  764. * 设置"bucketIndex"位置的元素为"新Entry" 设置"e"为"新Entry的下一个节点"
  765. */
  766. table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
  767. /**
  768. * 若HashMap的实际大小 不小于 "阈值" >=threshold 则调整HashMap的大小
  769. */
  770. if (size++ >= threshold)
  771. resize(2 * table.length);
  772. }
  773.  
  774. /**
  775. * @Description: 创建Entry。将"key-value"插入指定位置。
  776. * @param hash
  777. * @param key
  778. * @param value
  779. * @param bucketIndex
  780. * @Autor: Jason
  781. */
  782. void createEntry(int hash, K key, V value, int bucketIndex) {
  783. //保存"bucketIndex"位置的值到"e"中
  784. Entry<K,V> e = table[bucketIndex];
  785. // 设置"bucketIndex"位置的元素为"新Entry",
  786. // 设置"e"为"新Entry的下一个节点"
  787. table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
  788. size++;
  789. }
  790.  
  791. /**
  792. * @Package:cn.ucaner.sourceanalysis
  793. * @ClassName:HashIterator
  794. * @Description: <p> HashIterator是HashMap迭代器的抽象出来的父类,实现了公共了函数 </p>
  795. * <note>它包含"key迭代器(KeyIterator)"、"Value迭代器(ValueIterator)"和"Entry迭代器(EntryIterator)"3个子类</note>
  796. * @Author: - Jason
  797. * @CreatTime:2018年6月27日 下午8:32:23
  798. * @Modify By:
  799. * @ModifyTime: 2018年6月27日
  800. * @Modify marker:
  801. * @version V1.0
  802. */
  803. private abstract class HashIterator<E> implements Iterator<E> {
  804. // 下一个元素
  805. Entry<K,V> next;
  806. // expectedModCount用于实现fast-fail机制。
  807. int expectedModCount;
  808. // 当前索引
  809. int index;
  810. // 当前元素
  811. Entry<K,V> current;
  812.  
  813. HashIterator() {
  814. expectedModCount = modCount;
  815. if (size > 0) { // advance to first entry
  816. Entry[] t = table;
  817. // 将next指向table中第一个不为null的元素。
  818. // 这里利用了index的初始值为0,从0开始依次向后遍历,直到找到不为null的元素就退出循环。
  819. while (index < t.length && (next = t[index++]) == null) ;
  820. }
  821. }
  822.  
  823. public final boolean hasNext() {
  824. return next != null;
  825. }
  826.  
  827. // 获取下一个元素
  828. final Entry<K,V> nextEntry() {
  829. if (modCount != expectedModCount)
  830. throw new ConcurrentModificationException();
  831. Entry<K,V> e = next;
  832. if (e == null)
  833. throw new NoSuchElementException();
  834.  
  835. // 注意!!!
  836. // 一个Entry就是一个单向链表
  837. // 若该Entry的下一个节点不为空,就将next指向下一个节点;
  838. // 否则,将next指向下一个链表(也是下一个Entry)的不为null的节点。
  839. if ((next = e.next) == null) {
  840. Entry[] t = table;
  841. while (index < t.length && (next = t[index++]) == null);
  842. }
  843. current = e;
  844. return e;
  845. }
  846.  
  847. // 删除当前元素
  848. public void remove() {
  849. if (current == null)
  850. throw new IllegalStateException();
  851. if (modCount != expectedModCount)
  852. throw new ConcurrentModificationException();
  853. Object k = current.key;
  854. current = null;
  855. HashMap.this.removeEntryForKey(k);
  856. expectedModCount = modCount;
  857. }
  858.  
  859. }
  860.  
  861. /**
  862. * @Package:cn.ucaner.sourceanalysis
  863. * @ClassName:ValueIterator
  864. * @Description: <p> value的迭代器</p>
  865. * @Author: - Jason
  866. * @CreatTime:2018年6月27日 下午8:30:04
  867. * @Modify By:
  868. * @ModifyTime: 2018年6月27日
  869. * @Modify marker:
  870. * @version V1.0
  871. */
  872. private final class ValueIterator extends HashIterator<V> {
  873. public V next() {
  874. return nextEntry().value;
  875. }
  876. }
  877.  
  878. /**
  879. * @Package:cn.ucaner.sourceanalysis
  880. * @ClassName:KeyIterator
  881. * @Description: <p> key的迭代器</p>
  882. * @Author: - Jason
  883. * @CreatTime:2018年6月27日 下午8:29:57
  884. * @Modify By:
  885. * @ModifyTime: 2018年6月27日
  886. * @Modify marker:
  887. * @version V1.0
  888. */
  889. private final class KeyIterator extends HashIterator<K> {
  890. public K next() {
  891. return nextEntry().getKey();
  892. }
  893. }
  894.  
  895. /**
  896. * @Package:cn.ucaner.sourceanalysis
  897. * @ClassName:EntryIterator
  898. * @Description: <p> Entry的迭代器</p>
  899. * @Author: - Jason
  900. * @CreatTime:2018年6月27日 下午8:29:50
  901. * @Modify By:
  902. * @ModifyTime: 2018年6月27日
  903. * @Modify marker:
  904. * @version V1.0
  905. */
  906. private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
  907. public Map.Entry<K,V> next() {
  908. return nextEntry();
  909. }
  910. }
  911.  
  912. /**
  913. * @Description: 返回一个"key迭代器"
  914. * @return Iterator<K>
  915. * @Autor: Jason
  916. * @Date: 2018年6月27日
  917. */
  918. Iterator<K> newKeyIterator() {
  919. return new KeyIterator();
  920. }
  921.  
  922. /**
  923. * @Description: 返回一个"value迭代器"
  924. * @return Iterator<V>
  925. * @Autor: Jason
  926. * @Date: 2018年6月27日
  927. */
  928. Iterator<V> newValueIterator() {
  929. return new ValueIterator();
  930. }
  931.  
  932. /**
  933. * @Description: 返回一个"entry迭代器"
  934. * @return Iterator<Map.Entry<K,V>>
  935. * @Autor: Jason
  936. * @Date: 2018年6月27日
  937. */
  938. Iterator<Map.Entry<K,V>> newEntryIterator() {
  939. return new EntryIterator();
  940. }
  941.  
  942. /**
  943. * HashMap的Entry对应的集合
  944. */
  945. private transient Set<Map.Entry<K,V>> entrySet = null;
  946.  
  947. /**
  948. * 返回"key的集合",实际上返回一个"KeySet对象"
  949. */
  950. /* public Set<K> keySet() {
  951. Set<K> ks = keySet;
  952. return (ks != null ? ks : (keySet = new KeySet()));
  953. } */
  954.  
  955. /**
  956. * @Package:cn.ucaner.sourceanalysis
  957. * @ClassName:KeySet
  958. * @Description: <p> Key对应的集合 </p>
  959. * <note>KeySet继承于AbstractSet,说明该集合中没有重复的Key</note>
  960. * @Author: - Jason
  961. * @CreatTime:2018年6月27日 下午8:26:34
  962. * @Modify By:
  963. * @ModifyTime: 2018年6月27日
  964. * @Modify marker:
  965. * @version V1.0
  966. */
  967. private final class KeySet extends AbstractSet<K> {
  968. public Iterator<K> iterator() {
  969. return newKeyIterator();
  970. }
  971. public int size() {
  972. return size;
  973. }
  974. public boolean contains(Object o) {
  975. return containsKey(o);
  976. }
  977. public boolean remove(Object o) {
  978. return HashMap.this.removeEntryForKey(o) != null;
  979. }
  980. public void clear() {
  981. HashMap.this.clear();
  982. }
  983. }
  984.  
  985. /**
  986. * 返回"value集合",实际上返回的是一个Values对象
  987. */
  988. /* public Collection<V> values() {
  989. Collection<V> vs = values;
  990. return (vs != null ? vs : (values = new Values()));
  991. } */
  992.  
  993. /**
  994. * @Package:cn.ucaner.sourceanalysis
  995. * @ClassName:Values
  996. * @Description: <p> value集合</p>
  997. * <note> Values继承于AbstractCollection,不同于"KeySet继承于AbstractSet"Values中的元素能够重复 因为不同的key可以指向相同的value </note>
  998. * @Author: - Jason
  999. * @CreatTime:2018年6月27日 下午8:25:27
  1000. * @Modify By:
  1001. * @ModifyTime: 2018年6月27日
  1002. * @Modify marker:
  1003. * @version V1.0
  1004. */
  1005. private final class Values extends AbstractCollection<V> {
  1006. public Iterator<V> iterator() {
  1007. return newValueIterator();
  1008. }
  1009. public int size() {
  1010. return size;
  1011. }
  1012. public boolean contains(Object o) {
  1013. return containsValue(o);
  1014. }
  1015. public void clear() {
  1016. HashMap.this.clear();
  1017. }
  1018. }
  1019.  
  1020. /**
  1021. * 返回"HashMap的Entry集合"
  1022. */
  1023. @Override
  1024. public Set<Map.Entry<K,V>> entrySet() {
  1025. return entrySet0();
  1026. }
  1027.  
  1028. /**
  1029. * @Description: 返回"HashMap的Entry集合",它实际是返回一个EntrySet对象
  1030. * @return Set<Map.Entry<K,V>>
  1031. * @Autor: Jason
  1032. * @Date: 2018年6月27日
  1033. */
  1034. private Set<Map.Entry<K,V>> entrySet0() {
  1035. Set<Map.Entry<K,V>> es = entrySet;
  1036. return es != null ? es : (entrySet = new EntrySet());
  1037. }
  1038.  
  1039. /**
  1040. * @Package:cn.ucaner.sourceanalysis
  1041. * @ClassName:EntrySet
  1042. * @Description: <p> EntrySet对应的集合 </p>
  1043. * <Core>EntrySet继承于AbstractSet,说明该集合中没有重复的EntrySet</Core>
  1044. * @Author: - Jason
  1045. * @CreatTime:2018年6月27日 下午8:24:26
  1046. * @Modify By:
  1047. * @ModifyTime: 2018年6月27日
  1048. * @Modify marker:
  1049. * @version V1.0
  1050. */
  1051. private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
  1052. public Iterator<Map.Entry<K,V>> iterator() {
  1053. return newEntryIterator();
  1054. }
  1055. public boolean contains(Object o) {
  1056. if (!(o instanceof Map.Entry))
  1057. return false;
  1058. Map.Entry<K,V> e = (Map.Entry<K,V>) o;
  1059. Entry<K,V> candidate = getEntry(e.getKey());
  1060. return candidate != null && candidate.equals(e);
  1061. }
  1062. public boolean remove(Object o) {
  1063. return removeMapping(o) != null;
  1064. }
  1065. public int size() {
  1066. return size;
  1067. }
  1068. public void clear() {
  1069. HashMap.this.clear();
  1070. }
  1071. }
  1072.  
  1073. /**
  1074. * @Description: java.io.Serializable的写入函数 将HashMap的"总的容量,实际容量,所有的Entry"都写入到输出流中
  1075. * @param s
  1076. * @throws IOException void
  1077. * @Autor: Jason
  1078. * @Date: 2018年6月27日
  1079. */
  1080. private void writeObject(java.io.ObjectOutputStream s) throws IOException {
  1081. Iterator<Map.Entry<K,V>> i =
  1082. (size > 0) ? entrySet0().iterator() : null;
  1083. // Write out the threshold, loadfactor, and any hidden stuff
  1084. s.defaultWriteObject();
  1085. // Write out number of buckets
  1086. s.writeInt(table.length);
  1087. // Write out size (number of Mappings)
  1088. s.writeInt(size);
  1089. // Write out keys and values (alternating)
  1090. if (i != null) {
  1091. while (i.hasNext()) {
  1092. Map.Entry<K,V> e = i.next();
  1093. s.writeObject(e.getKey());
  1094. s.writeObject(e.getValue());
  1095. }
  1096. }
  1097. }
  1098.  
  1099. /**
  1100. * @Description: java.io.Serializable的读取函数:根据写入方式读出 将HashMap的"总的容量,实际容量,所有的Entry"依次读出
  1101. * @param s
  1102. * @throws IOException
  1103. * @throws ClassNotFoundException void
  1104. * @Autor: Jason
  1105. * @Date: 2018年6月27日
  1106. */
  1107. private void readObject(java.io.ObjectInputStream s)throws IOException, ClassNotFoundException {
  1108. // Read in the threshold, loadfactor, and any hidden stuff
  1109. s.defaultReadObject();
  1110. // Read in number of buckets and allocate the bucket array;
  1111. int numBuckets = s.readInt();
  1112. table = new Entry[numBuckets];
  1113. // init(); // Give subclass a chance to do its thing.
  1114. // Read in size (number of Mappings)
  1115. int size = s.readInt();
  1116. // Read the keys and values, and put the mappings in the HashMap
  1117. for (int i=0; i<size; i++) {
  1118. K key = (K) s.readObject();
  1119. V value = (V) s.readObject();
  1120. putForCreate(key, value);
  1121. }
  1122. }
  1123.  
  1124. /**
  1125. * @Description: 返回"HashMap总的容量"
  1126. * @return int
  1127. * @Autor: Jason
  1128. * @Date: 2018年6月27日
  1129. */
  1130. int capacity() { return table.length; }
  1131.  
  1132. /**
  1133. * @Description: 返回"HashMap的加载因子"
  1134. * @return float
  1135. * @Autor: Jason
  1136. * @Date: 2018年6月27日
  1137. */
  1138. float loadFactor() { return loadFactor; }
  1139.  
  1140. //consider
  1141. public static void main(String[] args) {
  1142. //h & (length-1) 好处和效率是?可以细究
  1143. System.out.println(indexFor("jasonandy@hotmail.com".hashCode(), 16));
  1144. System.out.println(indexFor("Jason".hashCode(), 10));
  1145. }
  1146. }

  

Java数据结构HashMap的更多相关文章

  1. java数据结构-HashMap

    一直以来似乎都有一个错觉,认为map跟其他的集合类一样继承自Collection,其实不然,Map和Collection在结构层次上是没有任何关系的,通过查看源码可以发现map所有操作都是基于key- ...

  2. Java数据结构和算法(四)赫夫曼树

    Java数据结构和算法(四)赫夫曼树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 赫夫曼树又称为最优二叉树,赫夫曼树的一个 ...

  3. 转发 java数据结构之hashMap详解

    概要 这一章,我们对HashMap进行学习.我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap.内容包括:第1部分 HashMap介绍第2部分 HashMa ...

  4. 关于Java的数据结构HashMap,ArrayList的使用总结及使用场景和原理分析

    使用,必须要知道其原理,在课堂上学过散列函数的用法及其原理.但一直不知道怎么实践. 后来,在实际项目中,需要做一个流量分析预处理程序.每5分钟会接收到现网抓来的数据包并解析,每个文本文件大概200M左 ...

  5. [转]java 的HashMap底层数据结构

    java 的HashMap底层数据结构   HashMap也是我们使用非常多的Collection,它是基于哈希表的 Map 接口的实现,以key-value的形式存在.在HashMap中,key-v ...

  6. Java中的数据结构-HashMap

    Java数据结构-HashMap 目录 Java数据结构-HashMap 1. HashMap 1.1 HashMap介绍 1.1.1 HashMap介绍 1.1.2 HashMap继承图 1.2 H ...

  7. java数据结构之HashSet和HashMap(java核心卷Ⅰ读书笔记)

    增加 删除 remove方法,可以删除指定的一个元素. 查找 ********************* **************************** HashSet既不可以用 0 1 2 ...

  8. Java之HashMap在多线程情况下导致死循环的问题

    PS:不得不说Java编程思想这本书是真心强大.. 学习内容: 1.HashMap<K,V>在多线程的情况下出现的死循环现象   当初学Java的时候只是知道HashMap<K,V& ...

  9. 学习java之HashMap和TreeMap

    HashMap和TreeMap是Map接口的两种实现,ArrayDeque和LinkedList是Queue接口的两种实现方式.下面的代码是我今天学习这四个数据结构之后写的.还是不熟悉,TreeMap ...

随机推荐

  1. libmidas.so.2

    libmidas.so.2 libmidas.so.2文件,使DATASNAP FOR LINUX中间件,支持OleVariant格式的序列,使TDataSetProvider+TClientData ...

  2. 如何在Windows Server 2008服务器中把Tomcat启动程序添加到服务中

    转自:https://blog.51cto.com/zdytesting/2314093 tomcat所在的bin目录: 添加服务: service install service_name 移除服务 ...

  3. 简易的CRM系统案例之SpringMVC+JSP+MySQL+hibernate框架版本

    继续对上一版本进行改版,变成SpringMVC框架 简易的CRM系统案例之易的CRM系统案例之JSP+MySQL+SSH框架版本 src/spring.xml <?xml version=&qu ...

  4. linux下使用SVN上传项目

    linux下使用SVN上传项目 摘自:https://blog.csdn.net/puppet_/article/details/78259591 2017年10月17日 13:51:33 puppe ...

  5. 性能测试-Linux资源监控⽅式

    Linux资源监控⽅式 1. 命令 2. 第三⽅⼯具(nmon) 3. LR(需要安装RPC相应服务包和开启服务)(略)   ⼀.命令 ⽅式 1. top (系统资源管理器) 2. vmstat (查 ...

  6. Delphi下Treeview控件基于节点编号的访问

    有时我们需要保存和重建treeview控件,本文提供一种方法,通过以树结构节点的编号访问树结构,该控件主要提供的方法如下:      function GetGlobeNumCode(inNode:T ...

  7. 雨田家园 delphi 拆分字符串

    最近在使用Delphi开发一种应用系统的集成开发环境.其中需要实现一个字符串拆分功能,方法基本原型应该是:procedure SplitString(src: string ; ch: Char; v ...

  8. (八)Centos之文件搜索命令locate

    一.文件搜索命令locate locate优点是 搜索速度快 ,缺点是只能按文件名搜索: 1.1 新建一个文件   1.2 更新数据库 locate命令搜索的是 /var/lib/mlocate 下的 ...

  9. 基于OpenAM系列的SSO----基础

    基于OpenAM系列的SSO----基础   OpenAM简介:OpenAM是一个开源的访问管理.授权服务平台.由ForegeRock公司发起.OpenAM前身为OpenSSO,由SUN公司创建,现在 ...

  10. NodeJs本地搭建服务器,模拟接口请求,获取json数据

    最近在学习Node.js,虽然就感觉学了点皮毛,感觉这个语言还不错,并且也会一步步慢慢的学着的,这里实现下NodeJs本地搭建服务器,模拟接口请求,获取json数据. 具体的使用我就不写了,这个博客写 ...