HashTable原理和源码分析详解编程语言
2023-06-13 09:11:51 时间
上一篇文章《HashMap原理和源码分析》介绍了HashMap。比对着HashMap,来看一下HashTable的特性.
HashTable的特性源码解析
参数:
private transient HashtableEntry ?,? [] table;// 数组存储 private transient int count; // 结点的总数 private int threshold; // 扩容的临界值 private float loadFactor; // 默认是0.75,到达需要扩容的比例 private transient int modCount = 0; // 修改的次数,例如put、remove、clear等
从参数就可以看出跟HashMap大同小异,而且简洁了许多。
构造函数
public Hashtable() { this(11, 0.75f); // 默认构造函数,直接设定初始容量 public Hashtable(int initialCapacity, float loadFactor) { if (initialCapacity 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); if (loadFactor = 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal Load: "+loadFactor); if (initialCapacity==0) initialCapacity = 1; this.loadFactor = loadFactor; table = new HashtableEntry ?,? [initialCapacity];// 直接使用初始容量 // 原本 threhold = initialCapacity * loadFactor // 但是这里实际上设置threshold 为initialCapacity threshold = (int)Math.min(initialCapacity, MAX_ARRAY_SIZE + 1);
从上面构造函数可以看到,默认初始容量 = threshold = 11; 加载因子 = 0.75
put
增加或者修改一个节点
public synchronized V put(K key, V value) { if (value == null) { // 不支持value为null throw new NullPointerException(); // Makes sure the key is not already in the hashtable. HashtableEntry ?,? tab[] = table; int hash = key.hashCode(); // 直接hash求余 得到hash桶位置 int index = (hash 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") HashtableEntry K,V entry = (HashtableEntry K,V )tab[index]; // 遍历hash桶 for(; entry != null ; entry = entry.next) { // 找到对应key的节点 if ((entry.hash == hash) entry.key.equals(key)) { V old = entry.value; entry.value = value; return old; // 没有存在key,增加节点到一个新的hash桶 addEntry(hash, key, value, index); return null; // 没有存在key,增加节点到一个新的hash桶 private void addEntry(int hash, K key, V value, int index) { modCount++; // 操作数 + 1 HashtableEntry ?,? tab[] = table; if (count = threshold) { // 大于等于扩容临界值 // Rehash the table if the threshold is exceeded rehash();// 需要扩容 tab = table; hash = key.hashCode(); // 同样 直接hash求余 得到hash桶位置 index = (hash 0x7FFFFFFF) % tab.length; // Creates the new entry. @SuppressWarnings("unchecked") HashtableEntry K,V e = (HashtableEntry K,V ) tab[index]; // 添加节点到一个新的桶中 tab[index] = new HashtableEntry (hash, key, value, e); count++;
remove
移除节点
public synchronized V remove(Object key) { HashtableEntry ?,? tab[] = table; int hash = key.hashCode(); // 同样 直接hash求余 得到hash桶位置 int index = (hash 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") HashtableEntry K,V e = (HashtableEntry K,V )tab[index]; // 遍历hash桶内的链表 for(HashtableEntry K,V prev = null ; e != null ; prev = e, e = e.next) { // 从链表中移除节点 if ((e.hash == hash) e.key.equals(key)) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; count--; V oldValue = e.value; e.value = null; return oldValue; return null;扩容
hashTable的扩容
protected void rehash() { int oldCapacity = table.length; HashtableEntry ?,? [] oldMap = table; //新容量 = 旧容量 × 2 +1 int newCapacity = (oldCapacity 1) + 1; // 容量超过最大值 if (newCapacity - MAX_ARRAY_SIZE 0) { if (oldCapacity == MAX_ARRAY_SIZE) // Keep running with MAX_ARRAY_SIZE buckets return; newCapacity = MAX_ARRAY_SIZE; HashtableEntry ?,? [] newMap = new HashtableEntry ?,? [newCapacity]; modCount++;// 操作数 +1 // 这里是符合预期的,threhold = initialCapacity * loadFactor threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1); table = newMap; // 迁移所有旧的节点到新的hash桶中 for (int i = oldCapacity ; i-- 0 ;) { for (HashtableEntry K,V old = (HashtableEntry K,V )oldMap[i] ; old != null ; ) { // 遍历每个节点 HashtableEntry K,V e = old; old = old.next; // 计算出新的位置,插入到桶的首个节点 int index = (e.hash 0x7FFFFFFF) % newCapacity; e.next = (HashtableEntry K,V )newMap[index]; newMap[index] = e;
扩容:
容量增加为原来2倍+1; 将每个结点重新hash迁移到对应的新的hash桶中
这里的增加节点跟HashMap的链表有点不一样,hashTable是直接插入到链表的头部,hashMap是在尾部。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/19399.html
cjavaxml相关文章
- Guava 源码分析(Cache 原理【二阶段】)
- Android布局优化之ViewStub、include、merge使用与源码分析
- MyBatis框架:第五章:源码解析及Mapper接口方式的mybatis的增,删,改,查实现
- 从vue源码中学习观察者模式
- vue源码分析-动态组件
- vue源码分析-响应式系统工作原理
- 从react源码看hooks的原理_2023-03-01
- 【安全算法之SHA256】SHA256摘要运算的C语言源码实现
- 从源码角度看React-Hydrate原理
- Vue源码之数据响应式原理
- 在线客服系统的源码中Golang Gin框架实现IP白名单机制
- EVM 源码解析
- Linux源码学习笔记 day1 开机时如何加载系统?
- Spring源码阅读系列之一:Spring AOP原理(上)
- 【Android 内存优化】Android 原生 API 图片压缩原理 ( 图片质量压缩方法 | 查找 Java 源码中的 native 方法对应的 C++ 源码 )
- 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 | Instrumentation 源码分析 )
- 【Android 热修复】热修复原理 ( 多 Dex 打包机制 | 多 Dex 支持 | Dex 分包设置 | 开发和产品风格设置 | 源码资源 )
- 【Java 虚拟机原理】JDK 体系结构 | Java 源码运行原理 | Java 虚拟机内存
- Spring Boot 源码解读与原理剖析|文末赠书
- Redis学习之API学习及Jedis源码原理分析详解数据库
- Spring Aop 源码实现原理分析详解编程语言
- Hashtable实现原理及源码分析详解编程语言
- TreeSet实现原理及源码分析详解编程语言
- [转]prototype源码解读超强推荐