一、Set和Map关系

Set代表集合元素无序,集合元素不可重复的集合,Map代表一种由多个key-value组成的集合,map集合是set集合的扩展只是名称不同,对应如下

二、HashMap的工作原理

        HashMap基于hashing原理,通过put()和get()方法储存和获取对象。
        put()方法: 它调用键对象的hashCode()方法来计算hashcode值,系统根据hashcode值决定该元素在bucket位置。如果两个对象key的hashcode返回值相同,那他们的存储位置相同,如果这两个Entry的key通过equals比较返回true,新添加Entry的value将覆盖集合中原有Entry的value,但key不会覆盖;如果这两个Entry的key通过equals比较返回false,新添加的Entry将与集合中原有Entry形成Entry链,而且新添加Entry位于Entry链的头部。put源码如下: 
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则不行)。

HashMap是非synchronized,而Hashtable是synchronized,意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器。HashMap可以通过下面的语句进行同步:Map m = Collections.synchronizeMap(hashMap);
 
四、HashMap和HashSet的区别
HashSet实现了Set接口,它不允许集合中有重复的值,HashMap实现了Map接口,Map接口对键值对进行映射。
HashSet扩展了HashMap,所以底层还是用到map存储,存储实现同map一致,HashMap储存键值,HashSet存储对象。

java集合HashMap、HashTable、HashSet详解的更多相关文章

  1. 【java基础】java集合之HashTable,HashSet,HashMap

    [一]HashSet (1)HashSet内部维护的是一个HashMap,具体原理见java集合之HashMap [二]HashTable (1)HashTable内部维护的是一个Entry的数组.E ...

  2. JAVA集合LIST MAP SET详解

    1. 集合框架介绍 我们知道,计算机的优势在于处理大量的数据,在编程开发中,为处理大量的数据,必须具备相应的存储结构,之前学习的数组可以用来存储并处理大量类型相同的数据,但是通过上面的课后练习,会发现 ...

  3. Java集合04——fail-fast&fail-safe 详解

    在前几个回合中,我们已经详细了解过了 Java 集合中的List.Set 和 Map,对这部分内容感兴趣的朋友可以关注我的公众号「Java面典」了解.今天我们将为各位介绍集合的失败机制--fail-f ...

  4. Java集合——TreeMap源码详解

    )TreeMap 是一个有序的key-value集合,它是通过红黑树实现的.因为红黑树是平衡的二叉搜索树,所以其put(包含update操作).get.remove的时间复杂度都为log(n). (2 ...

  5. Java集合——HashMap,HashTable,ConcurrentHashMap区别

    Map:“键值”对映射的抽象接口.该映射不包括重复的键,一个键对应一个值. SortedMap:有序的键值对接口,继承Map接口. NavigableMap:继承SortedMap,具有了针对给定搜索 ...

  6. Java集合——LinkedHashMap源码详解

    个KV.LinkedHashMap不仅像HashMap那样对其进行基于哈希表和单链表的Entry数组+ next链表的存储方式,而且还结合了LinkedList的优点,为每个Entry节点增加了前驱和 ...

  7. Java集合——ArrayList源码详解

    ) ArrayList 实现了RandomAccess, Cloneable, java.io.Serializable三个标记接口,表示它自身支持快速随机访问,克隆,序列化. public clas ...

  8. Java集合——LinkedList源码详解

    )LinkedList直接继承于AbstractSequentialList,同时实现了List接口,也实现了Deque接口. AbstractSequentialList为顺序访问的数据存储结构提供 ...

  9. java的集合框架最全详解

    java的集合框架最全详解(图) 前言:数据结构对程序设计有着深远的影响,在面向过程的C语言中,数据库结构用struct来描述,而在面向对象的编程中,数据结构是用类来描述的,并且包含有对该数据结构操作 ...

  10. (7)Java数据结构--集合map,set,list详解

    MAP,SET,LIST,等JAVA中集合解析(了解) - clam_clam的专栏 - CSDN博---有颜色, http://blog.csdn.net/clam_clam/article/det ...

随机推荐

  1. C++中不能被重载的运算符介绍

    C/C++ 里大多数运算符都可以在 C++ 中被重载. C 的运算符中只有 . 和 ?:(以及 sizeof,技术上可以看作一个运算符)不可以被重载.C++ 增加了一些自己的运算符,除了 :: 和 . ...

  2. 02_Nginx基本配置与参数说明 + 辅助命令

     Nginx基本配置与参数说明,下面是nginx.conf配置文件 #运行用户 #user  nobody; worker_processes  2; #全局错误日志及PID文件 #error_l ...

  3. Java-ServletResponse-ServletResponseWrapper

    /** * Defines an object to assist a servlet in sending a response to the client. * The servlet conta ...

  4. 【58】Spring总结之注解(2)

    启用注解配置: 1.context:annotation-config 该配置表示启用注解. 2.context:component-scan base-package="." 该 ...

  5. DH密钥交换非对称加密

    迪菲-赫尔曼密钥交换(Diffie–Hellman key exchange,简称"D–H") 是一种安全协议. 它可以让双方在完全没有对方任何预先信息的条件下通过不安全信道建立起 ...

  6. 【55】java异常机制剖析

    一.为什么要使用异常 首先我们可以明确一点就是异常的处理机制可以确保我们程序的健壮性,提高系统可用率.虽然我们不是特别喜欢看到它,但是我们不能不承认它的地位,作用.有异常就说明程序存在问题,有助于我们 ...

  7. java获取时间

    string startTimeStr = ((String) jsonCampaign.get(configObj.getKeyword(config.START_TIME)));          ...

  8. 【模板】最近公共祖先(LCA)

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  9. oracle的for和i++

    很长时间没用oracle的储存了,这次用到一次i++i++的sql语句:declarei_1 number(30) :=0;begin i_1 :=i_1+1;//i_1=1 insert into ...

  10. 自动红眼移除算法 附c++完整代码

    说起红眼算法,这个话题非常古老了. 百度百科上的描述: "红眼"一般是指在人物摄影时,当闪光灯照射到人眼的时候,瞳孔放大而产生的视网膜泛红现象. 由于红眼现象的程度是根据拍摄对象色 ...