一、简介

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

二类图

public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, 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<K,V> entry = (Entry<K,V>)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<K,V> e = (Entry<K,V>) 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<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
Entry<K,V> e = old;//旧节点e
old = old.next;//链表下一个节点,用来判断是否终止第二层循环 //计算旧链表的hash 在新数组的位置
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
//旧节点 的next指向,新数组的下标的链表,头插
e.next = (Entry<K,V>)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<K,V> e = (Entry<K,V>)tab[index]; //这个for循环写的666,专门备注一下
/**
for语句格式(循环语句)
for(初始化语句;判断条件语句;控制条件语句){
循环体语句;
} 执行过程:         (1)执行初始化语句
        (2)执行判断条件语句,看返回值
                 若是true,则继续执行;
                 若是false,则循环结束。
        (3)执行循环体语句
        (4)执行控制条件语句
        (5)回到(2)继续执行语句
**/ /**
初始化语句: Entry<K,V> prev = null
只是 定义参数 prev 判断条件语句:e != null
判断链表不为空 控制条件语句:prev = e, e = e.next
第一遍循环完给 初始化语句定义的参数prev 赋值
在把参数e 指向下一个链表节点
*/
for(Entry<K,V> 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。

java集合-哈希表HashTable的更多相关文章

  1. Java中哈希表(Hashtable)是如何实现的

    Java中哈希表(Hashtable)是如何实现的 Hashtable中有一个内部类Entry,用来保存单元数据,我们用来构建哈希表的每一个数据是Entry的一个实例.假设我们保存下面一组数据,第一列 ...

  2. java集合-哈希表HashMap

    一.简介 HashMap是一个散列表,是一种用于存储key-value的数据结构. 二.类图 public class HashMap<K,V> extends AbstractMap&l ...

  3. Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例

    概要 前一章,我们学习了HashMap.这一章,我们对Hashtable进行学习.我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable.第1部分 Ha ...

  4. 【转】Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例

    概要 前一章,我们学习了HashMap.这一章,我们对Hashtable进行学习.我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable.第1部分 Ha ...

  5. 哈希表(hashtable)的javascript简单实现

    javascript中没有像c#,java那样的哈希表(hashtable)的实现.在js中,object属性的实现就是hash表,因此只要在object上封装点方法,简单的使用obejct管理属性的 ...

  6. 哈希表(Hashtable)简述

    一,哈希表(Hashtable)简述 在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似keyvalue的键值对,其中 ...

  7. c/c++ 哈希表 hashtable

    c/c++ 哈希表 hashtable 概念:用key去查找value 实现hash函数有很多方法,本文用除留余数法. 除留余数法的概念: 取一个固定的基数的余数,注意不能用偶数,用偶数的话,分布会不 ...

  8. C#中哈希表(HashTable)的用法详解以及和Dictionary比较

    1.  哈希表(HashTable)简述 在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似keyvalue的键值对, ...

  9. 转 C#中哈希表(HashTable)的用法详解

    看了一遍有关哈希表的文字,作者总结的真是不错 .收藏起来 1.  哈希表(HashTable)简述 在.NET Framework中,Hashtable是System.Collections命名空间提 ...

随机推荐

  1. [源码解析] 并行分布式框架 Celery 之架构 (1)

    [源码解析] 并行分布式框架 Celery 之架构 (1) 目录 [源码解析] 并行分布式框架 Celery 之架构 (1) 0x00 摘要 0x01 Celery 简介 1.1 什么是 Celery ...

  2. iovec结构体使用说明

    http://blog.163.com/lichuan0502@126/blog/static/9933534820111033228285/

  3. java进阶(40)--wait与notify(生产者与消费者模式)

    文档目录: 一.概念 二.wait的作用 三.notify的作用 四.生产者消费者模式 五.举例 ---------------------------------------分割线:正文------ ...

  4. 你真的了解Innodb存储引擎?

    前言 前几篇记录了如何查看SQL执行计划.数据库事务相关的知识点 除了这两个,数据库还有两个是非常重要的,必须要考的 就是存储引擎和索引 今天先记录以下InnoDB存储引擎相关的知识点 MySQL存储 ...

  5. Fundamentals of Power Electronics 目录

    Fundamentals of Power Electronics Translated By Siwei Yang (前六章翻译自Edition 2,后面部分翻译自Edition 3) Part I ...

  6. [Fundamental of Power Electronics]-PART I-5.不连续导电模式-5.3 Boost变换器实例

    5.3 Boost变换器实例 作为第二个示例,考虑图5.12的Boost变换器.让我们来确定不同模式的边界并且求解DCM下的电压变换比.此前在2.3节中分析了在CCM工作的Boost变换器的特性,并确 ...

  7. MyBatis笔记(三)

    1. ResultMap 查询结果为null:要解决属性和字段名不一致的问题 我们先来看下步骤: 数据库中的字段名 Java中的实体类 public class User {    private i ...

  8. 如果要做优化,CSS提高性能的方法有哪些?

    一.前言 每一个网页都离不开css,但是很多人又认为,css主要是用来完成页面布局的,像一些细节或者优化,就不需要怎么考虑,实际上这种想法是不正确的 作为页面渲染和内容展现的重要环节,css影响着用户 ...

  9. 华为云PB级数据库GaussDB(for Redis)揭秘第八期:用高斯 Redis 进行计数

    摘要:高斯Redis,计数的最佳选择! 一.背景 当我们打开手机刷微博时,就要开始和各种各样的计数器打交道了.我们注册一个帐号后,微博就会给我们记录一组数据:关注数.粉丝数.动态数-:我们刷帖时,关注 ...

  10. 0609-搭建ResNet网络

    0609-搭建ResNet网络 目录 一.ResNet 网络概述 二.利用 torch 实现 ResNet34 网络 三.torchvision 中的 resnet34网络调用 四.第六章总结 pyt ...