Java Map(hashmap)

目录

为什么使用集合框架?

hashmap

Hash:

hashmap的扩容机制

其他

Map 中的"?"是什么意思?

为什么要尽量避免数组扩容

 通过迭代器访问 hashmap中的value​

Collections工具类

SHA算法

用来检查密码

 局部敏感的散列算法


为什么使用集合框架?

变量多了,集合方便管理。集合就是一种数据结构+算法(API),提升开发效率。

hashmap

JDK1.8之前hashmap的数据结构是链表散列,也就是链表和数组的结合体。模型图:

 

  hash值就是通过hash算法计算出来的值,这个值就是一个内存地址(不是实际的物理地址)。

Hash:

  1. 一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。
  2. 这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
  3. 文末有一种hash算法的介绍  SHA算法

为什么hash表查找数据时间复杂度是O(1)

原理:

  1. Hash表采用一个映射函数 f : key —> address 将关键字映射到该记录在表中的存储位置,从而在想要查找该记录时,可以直接根据关键字和映射关系计算出该记录在表中的存储位置.
  2. 通常情况下,这种映射关系称作为Hash函数,而通过Hash函数和关键字计算出来的存储位置(注意这里的存储位置只是表中的存储位置,并不是实际的物理地址)称作为Hash地址.
  3. 比如上述例子中,假如联系人信息采用Hash表存储,则当想要找到“李四”的信息时,直接根据“李四”和Hash函数计算出Hash地址即可

entry对象的定义为
JDK1.8之后就hashmap的数据结构变成了  数组+链表+红黑树

 

hashmap的扩容机制

首先介绍几个概念

【bucket】桶:

数组中每一个位置上都放有一个桶, 每个桶里就是装一个链表或是红黑树 ,链表或是红黑树中可以有很多个元素(entry) ,这就是桶的意思。也就相当于把元素都放在桶中。
capacity 】容量
capacity 译为容量代表的数组的容量,也就是数组的长度,同时也是 HashMap 中桶的个数。默认值是16
size 】 大小
size 就是在该 HashMap 的实例中实际存储的元素的个数。
【loadFactor】加载因子:
装载因子用来衡量 HashMap 满的程度。 loadFactor 的默认值为0.75f 。计算 HashMap 的实时装载因子的方法为: size/capacity ,而不是占用桶的数量去除以 capacity

hashmap初始化默认是有16个桶,当添加一个元素时,通过散列函数生成hash值,也就是地址值,查看当前地址有没有元素,如果没有,就存在该地址的内存中,如果有,使用equals函数判断值是否相等,如果不相等,说明key不一样,那么就以链表的形式挂载在当前地址所存储的元素下,如果相等,则更新value即可。

当添加的元素数量size/capacity达到加载因子并且还要在对应数组位置上有元素时,便进行扩容,桶的数量变为原来的2倍。

loadFactor的大小一般为0.75,过大查找起来耗费时间多,过小空间耗费多。

loadFactor 加载因子是控制数组存放数据的疏密程度, loadFactor 越趋近于 1 ,那么数组中存放的数据(entry) 也就越多,也就越密,也就是会让链表的长度增加, loadFactor 越小,也就是趋近于 0 ,那么数组中存放的数据也就越稀,也就是可能数组中每个位置上就放一个元素。
那有人说,就把 loadFactor 变为 1最好吗,存的数据很多,但是这样会有一个问题,就是我们在通过 key 拿到我们的 value 时,是先通过 key的 hashcode 值,找到对应数组中的位置,如果该位置中有很多元素,则需要通过 equals来依次比较链表 中的元素,拿到我们的 value 值,这样花费的性能就很高,如果能让数组上的每个位置尽量只有一个元素 最好,我们就能直接得到 value 值了。
所以有人又会说,那把 loadFactor 变得很小不就好了,但是如果变 得太小,在数组中的位置就会太稀,也就是分散的太开,浪费很多空间,这样也不好,所以在 hashMap loadFactor 的初始值就是 0.75 ,一般情况下不需要更改它。

其他

hashmap有很多初始化函数,其中

public HashMap ( Map <? extends K , ? extends V > m ) {
// 初始化填充因子
this . loadFactor = DEFAULT_LOAD_FACTOR ;
// m 中的所有元素添加至 HashMap
putMapEntries ( m , false );
}

Map<? extends K, ? extends V> 中的"?"是什么意思?

map的key要是K类或者其子类的对象,value要是类V或者其子类的对象

为什么要尽量避免数组扩容

 通过迭代器访问 hashmap中的value

 可以看到  所有的key使用set来维护的,也就是说map中的key具有唯一性。

Collections工具类

Collections是一个工具类,里面提供了操作集合的很多方法,比如排序,查找,替换,直接调用即可。

Collectons 提供了多个 synchronizedXxx() 方法 · ,该方法可以将指定集合包装成线程同步的集合,从而解决多线程并发访问集合时的线程安全问题。
正如前面介绍的 HashSet TreeSet arrayList,LinkedList,HashMap,TreeMap 都是线程不安全的。
Collections 提供了多个静态方法可以把他们包装成线程同步的集合。

SHA算法

用于创建散列表的散列函数根据字符串生成数组索引, 而SHA根据字符串生成另一个字符串

用来检查密码

数据库中存着你密码的散列值,你登录时系统计算密码的散列值然后比较,而 不是直接判断密码是否相等。

 

 局部敏感的散列算法

部分资料来源:狂神说 、《算法图解》
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

trigger333

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值