【数据结构】9.java源码关于HashTable
1.hashtable的内部结构
基础存储数据的hash桶由Entry结构的数组存放
而entry数据结构,有hash,key和value,还有一个指向下一个节点的引用next对象

这里就和hashmap中的数据结构不一样了,hashmap中的数据结构是node,虽然结构上差不多,但是setvalue的非空判断和hashcode的散列取值都是和node不一样的
那么这些数据在什么时候用呢???
下面来一一了解
2.hashtable的构造函数
这里需要注意一下了,我们前面提到说hashmap中的构造函数,其实实际上是不对hash桶进行实例化的,但是hashtable不一样,他会直接实例化大小,并且实例化成你指定的大小
而且这里默认的初始化容器的大小是11,负载因子代销默认0.75,负载因子的作用就是规定最大容量:hash桶的大小*负载因子
public TestHashTable(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);
//至少设置为1
if (initialCapacity==0)
initialCapacity = 1;
this.loadFactor = loadFactor;
table = new Entry<?,?>[initialCapacity];
threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
}
3.hashtable的增加元素策略
1.这里的put方法加了synchronized修饰符,用来标识线程安全
2.这里进行put取索引位置的时候,是直接用的key的hashcode方法,并且对hashcode结果进行取正数(& 0x7FFFFFFF),然后对hash桶进行取余%
然后就是判断这个key是否存在于这个hash桶中,如果存在更新旧值,并返回旧值
不存在,那么就添加一个entry,所以put操作的关键就是addEntry
而我们add操作其实就是找到对应的散列位置,然后用头插法
private void addEntry(int hash, K key, V value, int index) {
modCount++;
Entry<?,?> tab[] = table;
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
hash = key.hashCode();
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) tab[index];
//头插法
tab[index] = new Entry<>(hash, key, value, e);
count++;
}
说实话,这里相比hashmap来说简单多了,主要是少了树化的操作
4.hashtable删除元素策略
删除就比较简单了,就是找到对应的索引位置,然后再查找链表,如果是头节点,直接把entry.next设置为索引位置的数据,如果不是,就要获取到pre节点,然后pre.next = entry.next
public synchronized V remove(Object key) {
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
for(Entry<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;
}
主要是for循环这个地方有点意思,其余的到还好,无非就是返回旧值而已
5.修改元素,查找元素
修改不多做操作了,和添加,删除操作差不多,只是没有里面的多余操作,就是找到元素就直接返回了
6.hashtable特殊操作
1.hashtable是允许放空键值的,也就是键和值都可以放null
2.还有hashtable是线程安全的
3.hashmap再1.8之后是数组+链表+红黑树,hashtable还是很光棍-》数组+链表
4.扩容需要说一下,hashmap会扩容到比设置值大的最小2次幂,hashtable就群魔乱舞随意了
5.hashmap和hashtable都是取余,但是有点不同,因为hashmap是2次幂,所以取余的方式不一样是:(n - 1) & hash,为什么这样,请复习hashmap源码分析。。。
7.hashtable的刷新扩容
protected void rehash() {
int oldCapacity = table.length;
Entry<?,?>[] oldMap = table;
//直接左移一位,也就是扩大2倍然后+1 =》 大小扩为 2n + 1
int newCapacity = (oldCapacity << 1) + 1;
if (newCapacity - MAX_ARRAY_SIZE > 0) { //Integer.MAX_VALUE - 8
if (oldCapacity == MAX_ARRAY_SIZE) //如果老的容量已经达到这个值,anemia继续保持
// Keep running with MAX_ARRAY_SIZE buckets
return;
newCapacity = MAX_ARRAY_SIZE; //否则设置为允许的最大值
}
//创建新的hash桶
Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
modCount++;
//设置新的阈值
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
table = newMap;
//遍历hash桶,从后往前
for (int i = oldCapacity ; i-- > 0 ;) {
//遍历所有索引下的链表,吧链表添加到新的hash桶上
for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
Entry<K,V> e = old;
old = old.next;
//先取正,然后取余
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = (Entry<K,V>)newMap[index];
newMap[index] = e;
}
}
}
总结一下吧:
说实话,看完hashtable没花多久时间,相比较hashmap给人的惊为天人的操作,hashtable相对来说就比较朴实无华了,唯一的几个亮点就是线程安全,然后。。。。
想不出来了,只能说存在即合理,不能说hashtable会比较low,也许是我眼拙,大道至简,也许没有那些花里胡哨的才是真正最实用的
参考:
https://juejin.im/post/5a03b258518825188e515d89
https://blog.csdn.net/yyc1023/article/details/80619623
【数据结构】9.java源码关于HashTable的更多相关文章
- java源码阅读Hashtable
1类签名与注释 public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, C ...
- 如何阅读Java源码 阅读java的真实体会
刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比 ...
- 如何阅读Java源码
刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动.源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比方吧, ...
- Java 源码学习线路————_先JDK工具包集合_再core包,也就是String、StringBuffer等_Java IO类库
http://www.iteye.com/topic/1113732 原则网址 Java源码初接触 如果你进行过一年左右的开发,喜欢用eclipse的debug功能.好了,你现在就有阅读源码的技术基础 ...
- [收藏] Java源码阅读的真实体会
收藏自http://www.iteye.com/topic/1113732 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我 ...
- Java源码解读(一)——HashMap
HashMap作为常用的一种数据结构,阅读源码去了解其底层的实现是十分有必要的.在这里也分享自己阅读源码遇到的困难以及自己的思考. HashMap的源码介绍已经有许许多多的博客,这里只记录了一些我看源 ...
- 【java集合框架源码剖析系列】java源码剖析之java集合中的折半插入排序算法
注:关于排序算法,博主写过[数据结构排序算法系列]数据结构八大排序算法,基本上把所有的排序算法都详细的讲解过,而之所以单独将java集合中的排序算法拿出来讲解,是因为在阿里巴巴内推面试的时候面试官问过 ...
- 如何阅读Java源码?
阅读本文大概需要 3.6 分钟. 阅读Java源码的前提条件: 1.技术基础 在阅读源码之前,我们要有一定程度的技术基础的支持. 假如你从来都没有学过Java,也没有其它编程语言的基础,上来就啃< ...
- Java源码阅读的真实体会(一种学习思路)
Java源码阅读的真实体会(一种学习思路) 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈 ...
随机推荐
- C#各版本新增加功能
本系列文章主要整理并介绍 C# 各版本的新增功能. C# 8.0 C#8.0 于 2019年4月 随 .NET Framework 4.8 与 Visual Studio 2019 一同发布,但是当前 ...
- 学习git使用网址
如何将本地项目上传到Github (随梦飞翔) https://www.cnblogs.com/smfx1314/p/8426115.html git学习 GUI https://blog.csdn. ...
- [PXE] Linux(centos6)中PXE 服务器搭建,PXE安装、启动及PXE理论详解
[PXE] Linux(centos6)中PXE 服务器搭建,PXE安装.启动及PXE理论详解 本篇blog主要讲述了[PXE] linux(centos)PXE无盘服务器搭建,安装,启动及pxe协议 ...
- linux初学者-普通磁盘分区篇
linux初学者-普通磁盘分区篇 磁盘是计算机的重要组成部分,是记录数据的场所.在使用磁盘时,经常需要对其进行分区来实现不同的用途.下文将介绍在linux系统中普通磁盘分区的方法. "fdi ...
- <java程序大集合>
1.以下关于开发java程序的描述错误的是(). A.开发java程序的步骤包括:编写源程序,编译,运行 B.编写的java源程序文件使用.java作为扩展名 C:java源文件经编译后,生成后娺为. ...
- On The Way—Step 2 Python入门之Python内容初始
2.1 输出 print() 打印一个字符串 print('你真好!') 打印变量内容 a = '你真好!' print(a) 结果都是:你真好! 2.2 变量 变量名字规则 只能用下划线.字 ...
- 异常处理 _this.setData is not a function
_this.setData is not a function;at api request success callback function TypeError: _this.setData is ...
- NPM - 检查并更新项目依赖的版本
原文地址:https://acme.top/nodejs-npm-check-updates 前言 经常会遇到 package.json 中的库有更新,但是太多一个一个的来很费事,幸好有个工具 npm ...
- Jmeter之CSS选择器/JQuery选择器关联
选择器: CSS选择器或JQuery选择器是Jmeter支持的两种语法,下面对其两种语法进行简单介绍 CSS选择器 JQuery选择器 Chrome - 复制CSS选择器 Google Chrome在 ...
- 关于报错:The Microsoft.ACE. Oledb.12.0 provider was not registered on the local computer
错误描述:The Microsoft.ACE. Oledb.12.0 provider was not registered on the local computer 最近在Web项目中做一个自动生 ...