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

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

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