博客
关于我
java集合-哈希表HashTable
阅读量:728 次
发布时间:2019-03-22

本文共 5592 字,大约阅读时间需要 18 分钟。

一、简介

HashTable也是一种key-value结构,key-value不允许null,并且这个类的几乎全部的方法都加上了synchronized锁,来保证并发安全,由于加了锁所以性能方面会比较低。

二类图

public class Hashtable
extends Dictionary
implements Map
, Cloneable, java.io.Serializable

也实现了Map接口,继承了java.util.Dictionary类,Dictionary类是一个抽象类,它定义了键映射到值的数据结构。

常用方法

添加单个元素 synchronized V put(K key, V value)

//添加单个元素    public synchronized V put(K key, V value) {        // Make sure the value is not null        if (value == null) {//value值非空判断            throw new NullPointerException();        }        // Makes sure the key is not already in the hashtable.        Entry
tab[] = table; //拿到key的hash值 int hash = key.hashCode(); //数组长度取模运算得到下标index int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry
entry = (Entry
)tab[index];//通过index下标取得节点entry for(; entry != null ; entry = entry.next) {//单链表entry开始遍历 //判断链表节点的hash跟key是否跟传入的key匹配 if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value;//找到对应链表节点,替换value值 entry.value = value; return old; } } //没有在链表中找到key存在的节点,单链表进行添加 addEntry(hash, key, value, index); return null; } //链表添加元素 private void addEntry(int hash, K key, V value, int index) { modCount++;//修改次数+1 Entry
tab[] = table; if (count >= threshold) {//HashTable长度超过了 阈值,进行扩容 // 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
e = (Entry
) tab[index];//根据下标取得链表节点 //链表头插 tab[index] = new Entry<>(hash, key, value, e); count++;//长度+1 } //扩容 protected void rehash() { int oldCapacity = table.length;//旧的数组长度 Entry
[] oldMap = table;//旧的数组 // overflow-conscious code //新数组的容量=旧数组长度*2+1 int newCapacity = (oldCapacity << 1) + 1; //判断新数组长度是否超过了最大值 if (newCapacity - MAX_ARRAY_SIZE > 0) { if (oldCapacity == MAX_ARRAY_SIZE)//旧数组长度超过了最大值,直接return; 后面扩容代码不走了 // Keep running with MAX_ARRAY_SIZE buckets return; newCapacity = MAX_ARRAY_SIZE;//新数组长度 超过了最大值,赋值设置的数组最大值 } //创建一个新的数组,长度是newCapacity Entry
[] newMap = new Entry
[newCapacity]; modCount++;//修改次数+1 threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);//计算下一次扩容的阈值 table = newMap;//新数组赋值给 HashTable //第一层for循环遍历 旧的数组 for (int i = oldCapacity ; i-- > 0 ;) { //第二层for循环遍历,旧数组对应的单链表 for (Entry
old = (Entry
)oldMap[i] ; old != null ; ) { Entry
e = old;//旧节点e old = old.next;//链表下一个节点,用来判断是否终止第二层循环 //计算旧链表的hash 在新数组的位置 int index = (e.hash & 0x7FFFFFFF) % newCapacity; //旧节点 的next指向,新数组的下标的链表,头插 e.next = (Entry
)newMap[index]; newMap[index] = e;//节点赋值给新数组 } } }

根据key获取元素 synchronized V get(Object key)

//获取元素的值    public synchronized V get(Object key) {        //HashTable的数组        Entry
tab[] = table; //取得key的hash int hash = key.hashCode(); //hash取模运算得到数组下标 int index = (hash & 0x7FFFFFFF) % tab.length; //循环遍历链表节点的hash值和key是否等于 传的参数key,匹配成功返回value值 for (Entry
e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return (V)e.value; } } return null;//没找到值,返回null }

删除元素

//删除元素 synchronized V remove(Object key)    public synchronized V remove(Object key) {        //HashTable的数组        Entry
tab[] = table; //取得key的hash int hash = key.hashCode(); //hash取模运算得到数组下标 int index = (hash & 0x7FFFFFFF) % tab.length; //根据下标取得链表 Entry
e = (Entry
)tab[index]; //这个for循环写的666,专门备注一下 /** for语句格式(循环语句) for(初始化语句;判断条件语句;控制条件语句){ 循环体语句; } 执行过程:        (1)执行初始化语句        (2)执行判断条件语句,看返回值                 若是true,则继续执行;                 若是false,则循环结束。        (3)执行循环体语句        (4)执行控制条件语句        (5)回到(2)继续执行语句 **/ /** 初始化语句: Entry
prev = null 只是 定义参数 prev 判断条件语句:e != null 判断链表不为空 控制条件语句:prev = e, e = e.next 第一遍循环完给 初始化语句定义的参数prev 赋值 在把参数e 指向下一个链表节点 */ for(Entry
prev = null ; e != null ; prev = e, e = e.next) { //判断这个链表节点的hash跟key是否跟传入的参数key 相等 if ((e.hash == hash) && e.key.equals(key)) { modCount++;//修改次数+1 //执行链表删除操作 if (prev != null) { prev.next = e.next;//把记录了上一个节点prev 的next指向当前要删除的节点的下一个节点 } else { //等于 false 说明匹配到了第一个节点,直接把首节点的下一个节点赋值给数组即可 tab[index] = e.next;// } count--;//HashTable长度-1 //临时变量oldValue接收value并返回 V oldValue = e.value; e.value = null;//等于null gc回收 return oldValue; } } return null;//HashTable没有这个key返回null }

小结

1、HashTable 是线程安全的;HashTable 内部的方法基本都经过synchronized 修饰。

2、HashTable 中 put 进的键值只要有一个 null,直接抛出 NullPointerException。

3、Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。

转载地址:http://tfywk.baihongyu.com/

你可能感兴趣的文章
有道云笔记 同步到我的博客园
查看>>
李笑来必读书籍整理
查看>>
Hadoop(十六)之使用Combiner优化MapReduce
查看>>
《机器学习Python实现_10_06_集成学习_boosting_gbdt分类实现》
查看>>
CoreCLR源码探索(八) JIT的工作原理(详解篇)
查看>>
C语言编译错误列表
查看>>
看明白这两种情况,才敢说自己懂跨链! | 喵懂区块链24期
查看>>
CentOS5 Linux编译PHP 报 mysql configure failed 错误解决办法
查看>>
python中列表 元组 字典 集合的区别
查看>>
Android DEX加固方案与原理
查看>>
iOS_Runtime3_动态添加方法
查看>>
Leetcode第557题---翻转字符串中的单词
查看>>
Problem G. The Stones Game【取石子博弈 & 思维】
查看>>
Java多线程
查看>>
openssl服务器证书操作
查看>>
我用wxPython搭建GUI量化系统之最小架构的运行
查看>>
selenium+python之切换窗口
查看>>
重载和重写的区别:
查看>>
搭建Vue项目步骤
查看>>
账号转账演示事务
查看>>