java集合HashMap、HashTable、HashSet详解
一、Set和Map关系
Set代表集合元素无序,集合元素不可重复的集合,Map代表一种由多个key-value组成的集合,map集合是set集合的扩展只是名称不同,对应如下
二、HashMap的工作原理
public V put(K paramK, V paramV) {
//如果key为空,调用putForNullKey方法
if (paramK == null)
return putForNullKey(paramV);
//根据key的keyCode计算Hash值
int i = hash(paramK.hashCode());
//搜索指定hash值的对应在table中的索引
int j = indexFor(i, this.table.length);
//如果j索引处的Entry不为空,通过循环遍历localEntry元素的下一个元素
for (Entry localEntry = this.table[j]; localEntry != null; localEntry = localEntry.next) {
Object localObject1;
//找到指定key与放入key相等(hash值相同,通过equals比较返回true)
if ((localEntry.hash == i)
&& ((((localObject1 = localEntry.key) == paramK) || (paramK
.equals(localObject1))))) {
Object localObject2 = localEntry.value;
localEntry.value = paramV;
localEntry.recordAccess(this);
return localObject2;
}
}
//如果j索引Entry为null,此处没有Entry
this.modCount += 1;
//将key、value添加到i索引处
addEntry(i, paramK, paramV, j);
return null;
} void addEntry(int paramInt1, K paramK, V paramV, int paramInt2) {
//获取指定bucketIndex索引处Entry
Entry localEntry = this.table[paramInt2];
//将新创建的Entry放入bucketIndex索引处,并让新的Entry指向原来的Entry
this.table[paramInt2] = new Entry(paramInt1, paramK, paramV, localEntry);
//如果map中的key-value数量超过
if (this.size++ >= this.threshold)
//table对象的长度扩充到2倍
resize(2 * this.table.length);
}
put方法三种情况,如图:
get()方法:当HashMap的每个bucket里存储的Entry只是单个Entry,即没有通过指针产生Entry链时,此时HashMap具有最好的性能。当程序通过key取出对应value时,系统先计算出该key的hashCode()返回值,再根据该hashCode返回值找出该key在table数组中的索引,然后取出该索引处的Entry,最后返回该key对应的value值。get源码如下:
public V get(Object paramObject) {
//如果key为空,调用getForNullKey取出对应的value
if (paramObject == null)
return getForNullKey();
//根据key的hashCode值计算hash码
int i = hash(paramObject.hashCode());
//直接取出table数组中指定索引处的值
Entry localEntry = this.table[indexFor(i, this.table.length)];
while (localEntry != null) {
Object localObject;
//如果该Entry的key与被搜索key相同
if ((localEntry.hash == i)
&& ((((localObject = localEntry.key) == paramObject) || (paramObject
.equals(localObject)))))
return localEntry.value;
//搜索该Entry链的下一个
localEntry = localEntry.next;
} return null;
}
从代码看出,HashMap的每个bucket里只有一个Entry,HashMap可以根据索引快速取出该bucket里的Entry。
在发生Hash冲突的情况下,单个bucket里存储的不是一个Entry,而是一个Entry链,系统只能按顺序遍历每个Entry,直到找到想搜索的Entry。
HashMap有两个参数影响其性能:
1. 初始容量和加载因子。默认初始容量是16,加载因子是0.75。容量是哈希表中桶(Entry数组)的数量,初始容量只是哈希表在创建时的容量。加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,通过调用rehash 方法将容量翻倍。
2. 加载因子过高虽然减少了空间开销,但同时也增加了查询成本(加载因子是表示Hsah表中元素的填满的程度.若:加载因子越大,填满的元素越多,好处是,空间利用率高了,但:冲突的机会加大了.反之,加载因子越小,填满的元素越少,好处是:冲突的机会减小了,但:空间浪费多了)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地降低rehash 操作次数。如果初始容量大于最大条目数除以加载因子(实际上就是最大条目数小于初始容量*加载因子),则不会发生 rehash 操作。
3.HashMap存放的元素越来越多,到达临界值(阀值)threshold时,就要对Entry数组扩容,这是Java集合类框架最大的魅力,HashMap在扩容时,新数组的容量将是原来的2倍,由于容量发生变化,原有的每个元素需要重新计算bucketIndex,再存放到新数组中去,也就是所谓的rehash。HashMap默认初始容量16,加载因子0.75,也就是说最多能放16*0.75=12个元素,当put第13个时,HashMap将发生rehash,rehash的一系列处理比较影响性能,所以当我们需要向HashMap存放较多元素时,最好指定合适的初始容量和加载因子,否则HashMap默认只能存12个元素,将会发生多次rehash操作。
三、HashMap和Hashtable的区别
HashMap和Hashtable都实现了Map接口,主要的区别有:线程安全性,同步(synchronization),以及速度。HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。
java集合HashMap、HashTable、HashSet详解的更多相关文章
- 【java基础】java集合之HashTable,HashSet,HashMap
[一]HashSet (1)HashSet内部维护的是一个HashMap,具体原理见java集合之HashMap [二]HashTable (1)HashTable内部维护的是一个Entry的数组.E ...
- JAVA集合LIST MAP SET详解
1. 集合框架介绍 我们知道,计算机的优势在于处理大量的数据,在编程开发中,为处理大量的数据,必须具备相应的存储结构,之前学习的数组可以用来存储并处理大量类型相同的数据,但是通过上面的课后练习,会发现 ...
- Java集合04——fail-fast&fail-safe 详解
在前几个回合中,我们已经详细了解过了 Java 集合中的List.Set 和 Map,对这部分内容感兴趣的朋友可以关注我的公众号「Java面典」了解.今天我们将为各位介绍集合的失败机制--fail-f ...
- Java集合——TreeMap源码详解
)TreeMap 是一个有序的key-value集合,它是通过红黑树实现的.因为红黑树是平衡的二叉搜索树,所以其put(包含update操作).get.remove的时间复杂度都为log(n). (2 ...
- Java集合——HashMap,HashTable,ConcurrentHashMap区别
Map:“键值”对映射的抽象接口.该映射不包括重复的键,一个键对应一个值. SortedMap:有序的键值对接口,继承Map接口. NavigableMap:继承SortedMap,具有了针对给定搜索 ...
- Java集合——LinkedHashMap源码详解
个KV.LinkedHashMap不仅像HashMap那样对其进行基于哈希表和单链表的Entry数组+ next链表的存储方式,而且还结合了LinkedList的优点,为每个Entry节点增加了前驱和 ...
- Java集合——ArrayList源码详解
) ArrayList 实现了RandomAccess, Cloneable, java.io.Serializable三个标记接口,表示它自身支持快速随机访问,克隆,序列化. public clas ...
- Java集合——LinkedList源码详解
)LinkedList直接继承于AbstractSequentialList,同时实现了List接口,也实现了Deque接口. AbstractSequentialList为顺序访问的数据存储结构提供 ...
- java的集合框架最全详解
java的集合框架最全详解(图) 前言:数据结构对程序设计有着深远的影响,在面向过程的C语言中,数据库结构用struct来描述,而在面向对象的编程中,数据结构是用类来描述的,并且包含有对该数据结构操作 ...
- (7)Java数据结构--集合map,set,list详解
MAP,SET,LIST,等JAVA中集合解析(了解) - clam_clam的专栏 - CSDN博---有颜色, http://blog.csdn.net/clam_clam/article/det ...
随机推荐
- JQuery实战总结二 横向纵向菜单下拉效果图
记得以前在浏览了大多数网站的上面发现很多下拉的导航栏,觉得特别好玩,毕竟咱们是学习编程的嘛,对这下拉的效果还是挺感兴趣的,这种淡入淡出,随着鼠标移动的位置不同.有无等而出现不同的效果,给用户以神美感. ...
- Android For JNI(六)——交叉编译,NDK概述以及文件结构,编写自己的第一个JNI工程
Android For JNI(六)--交叉编译,NDK概述以及文件结构,编写自己的第一个JNI工程 终于回到我们的 android了,我们先要配置这个NDK的环境,但是之前,我们还要了解一下基本的术 ...
- Unity3D学习笔记(一)GUI控件的调用
GUI控件:1.在Start中初始化,在OnGUI中调整.2.公有变量才会出现在Inspector面板.3.GUI控件的初始化和处理在OnGUI内完成.4.JavaScript的中文为UTF-8编码可 ...
- 任务管理器中的PID找不到
PID是Process ID的简称,这对WINDOWS开发人员来说是非常有用的信息,但对于普通用户来说则根本不必去理会. 举个例子来说: 在网站发布的时候,需要安装IIS,那么iis的tcp的80 ...
- Linux配置文件系统及程序的限制 - ulimit
想象一个状况:我的 Linux 主机里面同时登陆了十个人,这十个人不知怎么搞的, 同时开启了 100 个文件,每个文件的大小约 10MBytes ,请问一下, 我的 Linux 主机的内存要有多大才够 ...
- 内核调试神器SystemTap — 更多功能与原理(三)
a linux trace/probe tool. 官网:https://sourceware.org/systemtap/ 用户空间 SystemTap探测用户空间程序需要utrace的支持,3.5 ...
- Sencha touch 2 入门 -------- DataView 显示服务器端JSON文件数据
今天学习了下DataView如何显示JSON文件数据,废话不多说,直接贴代码: 首先看下文件目录: 然后看下我们要处理的JSON文件,bookInfo.json. { "success&qu ...
- ionic3-ng4学习见闻--(轮播图完美方案)
ionic上 轮播图是最坑的插件了吧,各种bug和 问题. 事件也不好用.. 于是,我终于搞出来了一个完美的方案, 适用于,动态获取轮播图数据,自动循环播放,跳转其他页面回来后自动播放,手指触摸后自动 ...
- java面试笔试题大汇总
第一,谈谈final, finally, finalize的区别. 最常被问到. 第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以 ...
- java web--DOM
Dom总结dom:文档对象模型的简称.dom的解析:与XML一样遵循同样的规范 将标记型文档解析成一棵DOM树,并将树中的内容都封装成节点对象. 如果html文档过大,同样会造成解析过慢,怎么使用sa ...