Java 常用数据集合使用场景及特性小结————第一篇(HashMap)

         在java项目开发中,我们经常用到的数据集合HashMap,相信每一位开发人员的使用过,那么小菜在这里谈一下接下来的我的hashMap的一些小结。我们先来看看这些问题,什么是hashMap?hashMap的原理是什么?hashMap的数据结构?hashMap的常用的接口方法有那些?hashMap有那些构造函数?hashMap的初始长度是多少?为什么这样规定,设置这样的初始长度有什么意义?在高并发的情况下,为什么hashMap会出现死锁?在java8中,对hashMap有着怎样的优化?hashMap的几种遍历方式?那么,接下来,让我们带着这些问题往下看,GO

1、什么是HashMap?

       1、HashMap是基于哈希表的Map接口的非同步实现,是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry。这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干。

       2、HashMap中元素的key是唯一的,value值可重复。

       3、HashMap中允许使用null值和null键。

       4、HashMap中的元素是无序的。

       5、由于hashMap是非同步实现的,这就意味着它不是线程安全的。

       6、hashMap继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口。

2、HashMap的原理是什么?

        HashMap是基于hash算法实现的,通过put(key,value)存储对象到HashMap中,也可以通过get(key)从HashMap中获取对象。

        当我们使用put的时候,首先HashMap会对key的hashCode()的值进行hash计算,根据hash值得到这个元素在数组中的位置(即下标),将元素存储在该位置的链表上。当我们put元素的时候,如果key存在,key不会被覆盖,新的value会代替旧的value,该方法返回的是旧的value。如果key不存在,该方法返回的是null。

        当我们使用get的时候,首先HashMap会对key的hashCode()的值进行hash计算,根据hash值得到这个元素在数组中的位置,将元素从该位置上的链表中取出。通过key的equals方法对应 的位置的链表中找到需要的元素。

3、HashMap的数据结构

      HashMap是一个“链表散列”的数据结构,即数组和链表的结合体。如下图所示:

      

      从图中看出,HashMap底层就是一个数组结构,数组中的每一项又是一个链表,当新建一个 HashMap 的时候,就会初始化一个数组,我们可以查看HashMap源码,在构造函数中

       如上图所示红色框内的代码table = new Entry[capacity];创建了一个 Entry 的数组,也就是图中的table数组,那么 Entry 又是什么结构呢?

Entry是一个static class,其中包含了 key 和 value,也就是键值对,另外还包含了一个next的Entry指针。我们可以总结出Entry就是数组中的元素,每个Entry其实就是一个key-value对,它持有一个指向下一个元素的引用,这就构成了链表

4、HashMap常用的接口方法有那些

    clear():清空HashMap。它是通过将所有的元素设为null来实现的;
    containsKey():判断HashMap是否包含key;
    containsValue():判断HashMap是否包含“值为value”的元素;
    entrySet()、values()、keySet():返回“HashMap中所有对应的集合”,它是一个集合;
    get():获取key对应的value;
    put():对外提供接口,让HashMap对象可以通过put()将“key-value”添加到HashMap中;
    putAll():将"m"的全部元素都添加到HashMap中;
    remove():删除“键为key”元素。

5、HashMap有那些构造函数

    HashMap共包括4个构造函数;
    public HashMap()// 默认构造函数;
    public HashMap(int initialCapacity, float loadFactor) / /指定“容量大小”和“加载因子”的构造函数;
    public HashMap(int initialCapacity) // 指定“容量大小”的构造函数;
    public HashMap(Map<? extends K, ? extends V> m) // 包含“子Map”的构造函数,将m中的全部元素逐个添加到HashMap中;

6、HashMap的初始长度是多少?为什么这样规定,设置这样的初始长度有什么意义

     初始长度是 16,每次扩展或者是手动初始化,长度必须是 2的幂。
     因为: index = HashCode(Key) & (length - 1), 如果 length是 2的 幂的话,则 length - 1就是 全是 1的二进制数,比如  16 - 1 = 1111,这样相当于是 坐落在长度为 length的hashMap上的位置只和 HashCode的后四位有关,这只要给出的HashCode算法本身分布均匀,算出的index就是分布均匀的。
    因为HashMap的key是int类型,所以最大值是2^31次方,但是查看源码,当到达 2^30次方,即 MAXIMUM_CAPACITY,之后,便不再进行扩容。

     集合初始化时, 指定集合初始值大小。
     说明: HashMap使用HashMap(int initialCapacity)初始化,
     正例:initialCapacity = (需要存储的元素个数 / 负载因子) + 1。注意负载因子(即loader factor)默认为0.75, 如果暂时无法确定初始值大小,请设置为16(即默认值)。
      反例:HashMap需要放置1024个元素,由于没有设置容量初始大小,随着元素不断增加,容量7次被迫扩大,resize需要重建hash表,严重影响性能。

7、在高并发的情况下,为什么hashMap会出现死锁

    我们知道默认HashMap的初始长度是16,比较小,每一次push的时候,都会检查当前容量是否超过 预定的 threshold,如果超过,扩大HashMap容量一倍,整个表里的所有元素都需要按照新的hash算法被算一遍,这个代价较大。提到死锁,对于HashMap来说,貌似只能和链表操作有关。

8、在java8中,对hashMap有着怎样的优化

     简单说: java7中 hashMap每个桶中放置的是链表,这样当hash碰撞严重时,会导致个别位置链表长度过长,从而影响性能。
     java8中,HashMap 每个桶中当链表长度超过8之后,会将链表转换成红黑树,从而提升增删改查的速度。

9、HashMap的值获取的几种遍历方法

      请看正面的代码示例:在使用过程中推荐使用第二第三种

// 例 测试使用的hashMap
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("a", "001");
hashMap.put("b", "001");
hashMap.put("c", "003");
hashMap.put("d", "004");

// 第一种:普通使用,二次取值
System.out.println("\n通过Map.keySet遍历key和value:");
for (String key : hashMap.keySet()) {
	System.out.println("Key: " + key + " Value: " + hashMap.get(key));
}

// 第二种
System.out.println("\n通过Map.entrySet使用iterator遍历key和value: ");
Iterator map1it = hashMap.entrySet().iterator();
while (map1it.hasNext()) {
	HashMap.Entry<String, String> entry = (Entry<String, String>) map1it.next();
	System.out.println("Key: " + entry.getKey() + " Value: " + entry.getValue());
}

// 第三种:推荐,尤其是容量大时
System.out.println("\n通过Map.entrySet遍历key和value");
for (Entry<String, Object> entry : hashMap.entrySet()) {
	System.out.println("Key: " + entry.getKey() + " Value: " + entry.getValue());
}

// 第四种
System.out.println("\n通过Map.values()遍历所有的value,但不能遍历key");
for (Object v : hashMap.values()) {
	System.out.println("The value is " + v);
}

关于hashMap的介绍就到这里,如有不对的地方,欢迎大家提出我来改正,后面将会介绍其他数据集合类型,如果对你有帮助,欢迎在来哟,让我们一起进步!后续将为大家带来Hashtable、treeMap等,后续章节不见不散。

1)、Java 常用数据集合使用场景及特性小结————第二篇(HashTable)https://blog.csdn.net/qq_28245087/article/details/89672796

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值