热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【Java基础提高】HashTable源码分析(六)

一、HashTable1.1简介HashTable是一个数组和链表的结合体(在数据结构称“链表散列“)。大家都知道数组的查询效率高,移除效率低。而链表恰恰相反,所以将2者结合在一起来使用互

一、HashTable

   1.1 简介

  HashTable是一个数组和链表的结合体(在数据结构称“链表散列“)。大家都知道数组的查询效率高,移除效率低。而链表恰恰相反,所以将2者结合在一起来使用互相弥补了双方的缺点,效果更佳。

   1.2 类图

                 

   1.3 源码分析

   1.3.1 属性与链表节点类

/**
* 一个单向链表数组,哈希表的"key-value键值对"都是存储在Entry数组中的。
*/
private transient Entry[] table;

/**
* 保存键值对数量
*/
private transient int count;

/**
* Hashtable的阈值,用于判断是否需要调整Hashtable的容量。threshold的值="容量*加载因子"
*/
private int threshold;

/**
*加载因子
*/
private float loadFactor;

/**
* 用来实现fail-fast机制的
*/
private transient int modCount = 0;

//HashTable的节点,用来存储键值对。
//Entry是一个单向链表
private static class Entry implements Map.Entry {
//哈希值
int hash;
//存储的key和值value
final K key;
V value;
// 指向的下一个Entry,即链表的下一个节点
Entry next;

protected Entry(int hash, K key, V value, Entry next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
}

   1.3.2 put()操作

  put方法的工作原理是用key和hash计算出bucketIndex,在通过bucketIndex从数组中快速找到链表第一个节点位置,然后遍历这个链表直到找到相应的hash和key。如果位置上存在元素,则直接更新节点上的旧value值,并返回旧值。如果不存在,则将节点Entry存放到bucketIndex位置上。


//往HashTable中添加元素,多线程下put操作是安全的
public synchronized V put(K key, V value) {
// HashTable不能插入null元素
if (value == null) {
throw new NullPointerException();
}

//计算出bucketindex,然后通过bucketindex来查找数组中的位置。如果位置上已经存在元素,则直接替换更新value
Entry tab[] = table;
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V old = e.value;
e.value = value;
return old;
}
}

modCount++;
//当容器中的元素数量超过阈值时,重新分配容器大小
if (count >= threshold) {
//
rehash();

tab = table;
hash = hash(key);
index = (hash & 0x7FFFFFFF) % tab.length;
}

//创建一个新节点
Entry e = tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
return null;
}

   1.3.2 rehash()操作

//重新分配HashTable的空间大小,并将旧空间元素拷贝到新空间
protected void rehash() {
//定义一个oldMap节点存储旧空间,为下一步拷贝操作
int oldCapacity = table.length;
Entry[] 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;
}
Entry[] newMap = new Entry[newCapacity];

modCount++;
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
boolean currentAltHashing = useAltHashing;
useAltHashing = sun.misc.VM.isBooted() &&
(newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
boolean rehash = currentAltHashing ^ useAltHashing;

table = newMap;
//将旧空间元素拷贝到新创建的空间
for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry old = oldMap[i] ; old != null ; ) {
Entry e = old;
old = old.next;

if (rehash) {
e.hash = hash(e.key);
}
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = newMap[index];
newMap[index] = e;
}
}
}

   1.3.3 get()操作

//从HashTable中查找key对应的值,再在线程下它也是安全的
public synchronized V get(Object key) {
Entry tab[] = table;
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return e.value;
}
}
return null;
}

   1.3.4 remove()操作


//移除指定位置元素,多线程下是安全的
public synchronized V remove(Object key) {
Entry tab[] = table;
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
modCount++;
//将prev的下一个节点指向被移除节点的下一个节点
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
count--;
V oldValue = e.value;
e.value = null;
return oldValue;
}
}
return null;
}

作者:小毛驴,一个游戏人 
梦想:世界和平   
原文地址:http://blog.csdn.net/liulongling
    本博客中未标明转载的文章归作者小毛驴所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

推荐阅读
  • HashTable与ConcurrentHashMap均可实现HashMap的功能,对外提供了键值对存储的数据结构。但是在内部结构及实现上有何区别,性能上的差异到底在哪里又是如何导致的 ... [详细]
  • 要讨论这些常用的默认初始容量和扩容的原因是:当底层实现涉及到扩容时,容器或重新分配一段更大的连续内存(如果是离散分配则不需要重新分配,离散分配都是插入新元素时动态分配内存),要将容器原来的数据全部复 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • Spring框架《一》简介
    Spring框架《一》1.Spring概述1.1简介1.2Spring模板二、IOC容器和Bean1.IOC和DI简介2.三种通过类型获取bean3.给bean的属性赋值3.1依赖 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复hashMap是hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区 ... [详细]
  • 集合类中只能存放对象,而不能存放原始数据类型的元素,所以当有原始数据类型需要存放时,只能将其转换成相应的包装类对象。1)访问和遍历数组元素时,ArrayList的 ... [详细]
  • 一、HashMap1.HashMap概述:HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是 ... [详细]
  • HashMap和Hashtable的区别主要的区别有三点:线程安全性,同步(synchronization),以及速度。(两者都是无序排放)HashMap几乎可以等价于Hashtable,除了Hash ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 集合的遍历方式及其局限性
    本文介绍了Java中集合的遍历方式,重点介绍了for-each语句的用法和优势。同时指出了for-each语句无法引用数组或集合的索引的局限性。通过示例代码展示了for-each语句的使用方法,并提供了改写为for语句版本的方法。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • hashmap线程不安全允许有null的键和值效率高一点、方法不是Synchronize的要提供外同步有containsvalue和containsKey方法HashMap是Java1 ... [详细]
author-avatar
何霞2502856453_910
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有