HashMap详解

了解HashMap之前,我们要先了解Map和Hash表

什么是Map?

map就是用于存储键值对(<key,value>)的集合类,也可以说是一组键值对的映射(数学概念)。在java中map是一个接口,是和collection接口同一等级的集合根接口。

Map的存储结构:

下图就是Map的存储结构图,keyset(键的集合)和values(值的集合),每一条记录都是一个entry(一个键值对)。

Map的特点:

(1)没有重复的key,因为key是set保持的,是唯一的,无序的,如果key相同则会作为覆盖value处理。

(2)一个key只能对应一个value,一个value可以对应多个key,就好比射箭,很多人设一个靶子,每个人只能射这一个靶子,但是这个靶子可以让很多人射。

(3)key,value可以是任何的引用类型(包括null)

了解map接口之后,我们来了解一下hash表:

什么是Hash表?

在将键值对存入数组之前,将key通过哈希算法计算出哈希值,把哈希值作为数组下标,把该下标对应的位置作为键值对的存储位置,通过该方法建立的数组就叫做哈希表,而这个存储位置就叫做桶(bucket)。通俗一点讲就是顺序表和链表的组成(数组+单链表)

hash表的数据表现形式:数组+链表

Node<K,V> [] table;//数组,方便查找数据

class Node<K,V>{

final int hash;//hash值,查找或者删除,用来判断hash值是否相等

K   key;//key,查找或者删除用来判断输入的key值是否相等(==或者equals)

V   value;//value

Node<K,V> next;//指向的下一个节点

}

什么是HashMap?

HashMap是用哈希表(直接一点可以说数组加单链表)+红黑树实现的map类。

HashMap的存储结构:

HashMap的特点:

1、底层实现是 链表数组,JDK 8 后又加了 红黑树

2、实现了 Map 全部的方法

3、key 用 Set 存放,所以想做到 key 不允许重复,key 对应的类(一般是String)需要重写 hashCode 和 equals 方法

4、允许空键和空值(但空键只有一个,且放在第一位,知道就行)

5、元素是无序的,而且顺序会不定时改变(每次扩容后,都会重新哈希,也就是key通过哈希函数计算后会得出与之前不同的哈希值,这就导致哈希表里的元素是没有顺序,会随时变化的,这是因为哈希函数与桶数组容量有关,每次结点到了临界值后,就会自动扩容,扩容后桶数组容量都会乘二,而key不变,那么哈希值一定会变)

6、插入、获取的时间复杂度基本是 O(1)(前提是有适当的哈希函数,让元素分布在均匀的位置)

7、遍历整个 Map 需要的时间与数组的长度成正比(因此初始化时 HashMap 的容量不宜太大)

8、两个关键因子:初始容量(CAPACITY =16)、加载因子(loadFactor = 0.75)、阈值 threshold = CAPACITY * LoadFactor

9、HashMap不是同步,HashTable是同步的,但HashTable已经弃用,如果需要线程安全,可以用synchronizedMap,例如            Map m = Collections.synchronizedMap(new HashMap(...));

HashMap的源码解析:增删改查

1、构造方法:

//创建一个空的哈希表,初始容量为 16,加载因子为 0.75

public HashMap()

//创建一个空的哈希表,指定容量,使用默认的加载因子

public HashMap(int initialCapacity)

//创建一个空的哈希表,指定容量和加载因子

public HashMap(int initialCapacity, float loadFactor)

//创建一个内容为参数 m 的内容的哈希表

public HashMap(Map<? extends K, ? extends V> m)

2、增:public V put(K key,V  value):

(1)判断key是否为空,如果是添加null key;

(2)通过hash()函数获取hash值;

(3)通过indexFor()函数找到hash值对应的table数组的下标index;注:

(4)从数组下标对应的节点开始用for循环,判断当前节点是否存在,存在返回oldValue;

(5)addEntry直接添加,modCount++;

注意:hash()方法获取的是hash值;indexFor()里面的返回:h&(length-1)与运算,相当于求余数。

3、public void addEntry(int hash,K key, V value,int bucketIndex)

(1)判断是否需要扩容,长度size大于阈值threshold并table数组下面不为空;扩容为table长度的两倍;重新获取hash值和table的脚标bucketIndex;

(2)创建节点

4、public void  createEntry(int hash,K key,V value, int bucketIndex):创建一个节点

(1)创建一个新的节点,放在表头;定义一个 节点e=table[bucketIndex];创一个新节点指向e;table[bucketIndex] =新节点。

5、public  V get(K key)

(1)判断key是否为空,是的话,返回null key 所对应的值。

(2)如果不是,则返回key所对应的节点。

(3)判断节点是否为空,不为空则返回节点中的value值。

6、根据key获取节点:public final Entry<K,V> getEntry(Object key)

(1)获取key的hash值,利用for循环,通过indexFor,找到table的脚标index,轮询index所对应的所有节点e.next;

(2)判断每个节点的hash,key是否相等,相等才返回 节点e。

HashMap的遍历方法:

1、采用keySet+for循环遍历:获取所有的key,再for循环获取value

Map<String,String> map=new HashMap<String,String>();

map.put("key1","value1");

map.put("key2","value2");

map.put("key3","value3");

for(String key:map.keySet()){

    system.out.println("key:"+key);

      system.out.println("value:"+map.get(key));

}

2、采用entrySet+for循环遍历;获取所有键值对,然后遍历

Set<Entry<String,String>> entries = map.entrySet();

for(Entry<String,String> entry: entries){

system.out.println("key:"+entry.getKey());

    system.out.println("value:"+entry.getValue());

}

3、采用entrySet+iterator;用迭代器

Iterator< Map.Entry<String,String>> it=map.EntrySet().iterator();

while(it.hasNext()){

    Map.Entry<String,String> entry=it.next();

    system.out.println("key:"+entry.getKey());

    system.out.println("value:"+entry.getValue());

}

4、获取所有的value,但是无法获取key

for(String value:map.values()){ system.out.println("value:"+value);

到此介绍所HashMap全部结束!

部分内容转自:https://blog.csdn.net/qq_36711757/article/details/80394272

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容

  • HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,其中 ...
    Android看海阅读 251评论 0 0
  • JDK1.8对HashMap底层的实现进行了优化,例如引入红黑树的数据结构和扩容的优化等。本文结合JDK1.7和J...
    学编程的小屁孩阅读 255评论 0 0
  • 偶然发现这位博主的文章很干货,部分知识讲解非常细致,尤其是开讲之前的准备知识很方便小白直接理解HashMap;故复...
    Divenier阅读 373评论 0 4
  • 简介 Java为数据结构中的映射定义了一个接口java.util.Map,此接口主要有四个常用的实现类,分别是Ha...
    味道_3a01阅读 2,539评论 2 3
  • 摘要 HashMap是Java程序员使用频率最高的用于映射(键值对)处理的数据类型。随着JDK(Java Deve...
    国祥同学阅读 3,959评论 1 10