【数据结构】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),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈 ...
随机推荐
- 在Ubuntu中安装Docker和docker的使用
1.在Ubuntu中安装Docker 更新ubuntu的apt源索引 sudo apt-get update 安装包允许apt通过HTTPS使用仓库 sudo apt-get install \ ap ...
- Java IO部分面试题
1.什么是比特(Bit),什么是字节(Byte),什么是字符(Char),它们长度是多少,各有什么区别 1. Bit最小的二进制单位 ,是计算机的操作部分 取值0或者1 2. Byte是计算机操作数据 ...
- C#中使用split分割字符串的方法小结
string s=abcdeabcdeabcde; string[] sArray=s.Split(c) ; foreach(string i in sArray) Console.WriteLine ...
- NLP(十二)依存句法分析的可视化及图分析
依存句法分析的效果虽然没有像分词.NER的效果来的好,但也有其使用价值,在日常的工作中,我们免不了要和其打交道.笔者这几天一直在想如何分析依存句法分析的结果,一个重要的方面便是其可视化和它的图分析 ...
- 脱壳0-FSG壳-详细流程
目录 @ 1 拿到当前加壳程序,用exeinfo/PeID 看一下信息 可以看出是很老的壳FSG. 分析: Entry Point : 000000154,熟悉PE结构的知道,入口点(代码)揉进P ...
- $.ajax()在IE9下的兼容性问题
最近在主导一个项目,遇到了一点问题,跟大家分享一下. 最终bug解决方案的链接地址:http://stackoverflow.com/questions/5241088/jquery-call-to- ...
- TCP传输协议如何进行拥塞控制?
拥塞控制 拥塞现象是指到达通信子网中某一部分的分组数量过多,使得该部分网络来不及处理,以致引起这部分乃至整个网络性能下降的现象,严重时甚至会导致网络通信业务陷入停顿,即出现死锁现象.这种现象跟公路网中 ...
- spring注解不支持静态变量注入
spring注解不支持静态变量注入:今天敲代码 自动配置 配置: Animal.java package study01_autoconfig.beanConfig; import org.spri ...
- 洛谷P2763题解
吐槽一下:蜜汁UKE是什么玩意?! 题目分析: 观察题面,对于给定的组卷要求,计算满足要求的组卷方案,可以发现这是一道明显的有条件的二分图匹配问题,于是考虑建模. 建一个超级源点,一个超级汇点:源点与 ...
- Pandas 库之 DataFrame
How to use DataFrame ? 简介 创建 DataFrame 查看与筛选数据:行列选取 DataFrame 数据操作:增删改 一.About DataFrame DataFrame 是 ...