Hashtable /HashMap / LinkedHashMap 概述

* Hashtable比较早,是线程安全的哈希映射表。内部采用Entry[]数组,每个Entry均可作为链表的头,用来解决冲突(碰撞)。
* HashMap与Hashtable基本原理一样,只是HashMap允许null的key/value,且非线程安全。
* LinkedHashMap从字面看有两个意思,Hash和Linked,既通过Hash散列存储(与HashMap相同),又把每个Entry(增加了before/after指针)通过双向链表进行连接,记录元素插入的顺序。根据Key取数据,可按照HashMap的散列迅速定位Value;迭代时,可按照双向链表,高效遍历。
 

Hashtable 特点

* 线程安全。
* Key、Value均不能为null。
* 包含了一个Entry[]数组,而Entry又是一个链表,用来处理冲突。
* 每个Key对应了Entry数组中固定的位置(记为index),称为槽位(Slot)。槽位计算公式为: (key.hashCode() & 0x7FFFFFFF) % Entry[].length() 。
* 当Entry[]的实际元素数量(Count)超过了分配容量(Capacity)的75%时,新建一个Entry[]是原先的2倍,并重新Hash(rehash)。
* rehash的核心思路是,将旧Entry[]数组的元素重新计算槽位,散列到新Entry[]中。
 

Hashtable 源码简要分析

 
Entry类

  1. class Entry<K,V> // Entry<K,V>是槽中的元素,可做链表,解决散列冲突。
  2. {
  3. int hash; // 即key.hashCode()
  4. K key;
  5. V value;
  6. Entry<K,V> next; // 用来实现链表结构。同一链表中的key的hash是相同的。
  7. protected Entry(int hash, K key, V value, Entry<K,V> next) {
  8. this.hash=hash;this.key=key;this.value=value;this.next=next;
  9. }
  10. }

  

Hashtable类
  1. public class Hashtable<K,V>
  2. {
  3. Entry[] table; // 槽数组,也称桶数组。
  4. int count; // table中实际存放的Entry数量。
  5. int threshold; // 当table数量超过该阈值后,进行reash。(该值为 capacity * loadFactor)
  6. float loadFactor; // 加载因子,默认是0.75f。
  7.  
  8. public Hashtable(int initialCapacity/*默认是11*/, float loadFactor) {
  9. if(initialCapacity==0) initialCapacity=1;
  10. this.locadFactor = locadFactor;
  11. table = new Entry[initialCapacity];
  12. threshold = (int)(initialCapacity * locadFactor);
  13. }
  14.  
  15. // put(): 若key存在,返回旧value;若key不存在,返回null。
  16. public synchronized V put(K key,V value) {
  17. // 检查key是否已经存在,若存在则覆盖已经存在value,并返回被覆盖的value。
  18. Entry tab[] = table;
  19. int hash = key.hashCode();
  20. int index = (hash & 0x7FFFFFFF) % tab.length; // 存储槽位索引。
  21. for(Entry<K,V> e = tab[index]; e!=null; e=e.next ) { // 在冲突链表中寻找
  22. if( (e.hash == hash ) && e.key.equals(key) ) {
  23. V old = e.value;
  24. e.value = value; // 新value覆盖旧value
  25. return old;
  26. }
  27. }
  28.  
  29. // 是否需要rehash
  30. if(count >= threshold){
  31. rehash();
  32. tab = table; // rehash完毕后,修正tab指针指向新的Entry[]
  33. index = (hash & 0x7FFFFFFF) % tab.length; // 重新计算Slot的index
  34. }
  35.  
  36. // 存储到槽位,如果有冲突,新来的元素被放到了链表前面。
  37. Entry<K,V> e = tab[index]; // 旧有Entry
  38. tab[index] = new Entry<>(hash,key,value,e/* 旧有Entry成为了新增Entry的next */);
  39. count ++;
  40. return null;
  41. }
  42.  
  43. // rehash(): 再次hash。当Entry[]的实际存储数量占分配容量的约75%时,扩容并且重新计算各个对象的槽位
  44. static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 ;
  45. protected void rehash() {
  46. int oldCapacity = table.length;
  47. Entry[] oldMap = table;
  48. int newCapacity = (oldCapacity << 1) + 1; // 2倍+1
  49. Entry[] newMap = new Entry[newCapacity];
  50. threshold = (int)(newCapacity * loadFactor);
  51. table = newMap;
  52.  
  53. for( int i=oldCapacity; i-- >0;){ // i的取值范围为 [oldCapacity-1,0]
  54. for (Entry<K,V> old = oldMap[i]; old!=null;){ // 遍历旧Entry[]
  55. Entry<K,V> e = old;
  56. int index = (e.hash & 0x7FFFFFFF) % newCapacity; // 重新计算各个元素在新Entry[]中的槽位index。
  57. e.next = newMap[index]; // 已经存在槽位中的Entry放到当前元素的next中
  58. newMap[index]=e; // 放到槽位中
  59. old = old.next;
  60. }
  61. }
  62.  
  63. }
  64. }

  

References

JDK源码

[Java] Hashtable 源码简要分析的更多相关文章

  1. [Java] HashMap 源码简要分析

    特性 * 允许null作为key/value. * 不保证按照插入的顺序输出.使用hash构造的映射一般来讲是无序的. * 非线程安全. * 内部原理与Hashtable类似.   源码简要分析 pu ...

  2. [Java] LinkedHashMap 源码简要分析

    特点 * 各个元素不仅仅按照HashMap的结构存储,而且每个元素包含了before/after指针,通过一个头元素header,形成一个双向循环链表.使用循环链表,保存了元素插入的顺序. * 可设置 ...

  3. RxJava && Agera 从源码简要分析基本调用流程(2)

    版权声明:本文由晋中望原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/124 来源:腾云阁 https://www.qclo ...

  4. Activity源码简要分析总结

    Activity源码简要分析总结 摘自参考书籍,只列一下结论: 1. Activity的顶层View是DecorView,而我们在onCreate()方法中通过setContentView()设置的V ...

  5. Java - HashTable源码分析

    java提高篇(二五)-----HashTable 在java中与有两个类都提供了一个多种用途的hashTable机制,他们都可以将可以key和value结合起来构成键值对通过put(key,valu ...

  6. RxJava && Agera 从源码简要分析基本调用流程(1)

    版权声明:本文由晋中望原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/123 来源:腾云阁 https://www.qclo ...

  7. Java Hashtable 源码(JDK8)

    记录了HashMap也来看看Hashtable吧,最近打算换份实习,所以想看看书回顾一下,不然就快记不得了.....囧啊囧啊,记性太差怎么破??? Hashtable里面的一些变量: Entry< ...

  8. Elasticsearch之client源码简要分析

    问题 让我们带着问题去学习,效率会更高 1  es集群只配置一个节点,client是否能够自动发现集群中的所有节点?是如何发现的? 2  es client如何做到负载均衡? 3  一个es node ...

  9. Redis源码简要分析

    转载请注明来源:https://www.cnblogs.com/hookjc/ 把所有服务端文件列出来,并且标示出其作用:adlist.c //双向链表ae.c //事件驱动ae_epoll.c // ...

随机推荐

  1. python接口自动化测试十二:对返回的json的简单操作

    # 1.requests里面自带解析器转字典 print(r.json()) print(type(r.json())) # 取出json中的'result_sk_temp'字段 # {"r ...

  2. python 全栈开发,Day135(爬虫系列之第2章-BS和Xpath模块)

    一.BeautifulSoup 1. 简介 简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据.官方解释如下: ''' Beautiful Soup提供一些简单 ...

  3. python 全栈开发,Day6(is,小数据池,编码转换)

    一.is a = 100 b = 100 print(a == b) print(a is b) 执行输出: TrueTrue 查看内存地址,使用id函数 print(id(a)) print(id( ...

  4. C++传值、传引用

    C++传值.传引用 C++的函数参数传递方式,可以是传值方式,也可以是传引用方式.传值的本质是:形参是实参的一份复制.传引用的本质是:形参和实参是同一个东西. 传值和传引用,对大多数常见类型都是适用的 ...

  5. Javascript事件设计模式(七)

    一:事件设计概述 事件机制可以使程序逻辑更加符合现实世界,在JavaScript中很多对象都有自己的事件,例如按钮就有onclick事件,下拉列表框就有 onchange事件,通过这些事件可以方便编程 ...

  6. Queuing HDU2604

    一道递推题目 得到递推关系为  f[n]=f[n-1]+f[n-3]+f[n-4]; 用普通的枚举算法会超时 所以要用矩阵快速幂来加速 转化为矩阵即为: +1 0 1 1       F(N-1) F ...

  7. 6-17 看图写树 uva10562

    非常好的dfs题  有很多细节 关于‘ ’  ‘0’  ’\n‘  的处理  他们都属于isspace函数 其中 while(buf[x+2][i]=='-'&&buf[x+3][i] ...

  8. FZU 2150 Fire Game(双起点)【BFS】

    <题目链接> 题目大意: 两个熊孩子在n*m的平地上放火玩,#表示草,两个熊孩子分别选一个#格子点火,火可以向上向下向左向右在有草的格子蔓延,点火的地方时间为0,蔓延至下一格的时间依次加一 ...

  9. Java开发人员必须掌握的Linux命令(三)

    做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 学习应该是快乐的,在这个乐园中我努力让自己能用简洁易懂(搞笑有趣)的表达来讲解知识或者技术,让学习之旅充满乐趣,这就是写博 ...

  10. Ubuntu python Compression requires the (missing) zlib module

    描述: 在Ubuntu中安装setuptools时出现   Compression requires the (missing) zlib module 解决方法步骤: ①Ubuntu下安装zlib: ...