Map接口

Map接口

哈希表就是一种以键-值(key-indexed) 存储数据的结构,只要输入待查找的值即key,即可查找到其对应的值。

1.Map接口的定义

定义map对象时需要指定key和value对应的类型,必须是复杂类型,不能使用intmap接口中有一个内部接口为Entry:interface Entry<K ,V>封装所存储的key-value对数据。

interface entry<K,V>{
     K getKey(); //因为key决定数据的存放位置,一旦存储成功则key不允许修改
     V getValue();  //针对value提供get/set方法
     V setValue(V value);
     //存储的数据应该是可以进行等值判断的,key不允许重复
     boolean equals(Object o);
     int hashCode();

每个Entry对象中封装了一个key和value

2.Map接口中常见方法
(1)Object put(Objectkey, Object value):
用来存放一个键-值对Map中 ,如果出现key值冲突则后盖前。
允许key值和value值为null,但是key值为null只能有一个,value值为null没有个数限制.

(2)si ze() :int用于获取集合中的元素个数.

(3)Object remove(Object key):根据key(键),移除键-值对,并将值返回.

(4)Object get( Object key) :根据key(键)取得对应的值,如果key值不存在则返回为null

(5)boolean containsKey( Object key) :判断Map中是否存在某键key

(6)void clear() :清空当前Map中的元素

(7)boolean containsValue( Object value):判断Map中是否存在某值value

3.Map中的三种视图

key所组成的set、value所组成的collection、key-value的Entry集合Set

(1)public Set keySet() :返回所有的键key,并 使用Set容器存放,获取key值后就可以通过get方法获取key对应的值value;
(2)public Collection values() :返回所有的值Value,并使用Collection存放;
(3)public Set entrySet() :返回一个实现 Map.Entry 接口的元素 Set

forEach 和 Lambda表达式实现输出

4.Map实现类–HashMap

(1)类定义

public class HashMap<K,V>  extends AbstrctMap<K,V>
implements Map<K,V> ,Cloneable,Serializable{}

(2)相关的常量值

static cladd int DEFAULT_INITIAL_CAPACITY = 1 << 4 //默认初始化容积
static final int MAXIMUM_CAPACITY = 1 << 30; //最大容积
static final float DEFAULT_LOAD_FACTOR = 0.75f; //默认的加载因子值

静态 内部类用于实现Entry,Hah Map中存放的key /value对就 被封装为Node对象。其中key就是存放的键值,用于决定具体的存放位置;value是具体存放的数据,hash就是当前Node对象的hash值,next用于指向下一个Node节点(单向链表)具体存储数据的实现采用的是单向链

重要的阈值

static final int TREE IFY_ TH RESH OLD=8;//树化 阈值:即链表 转成红黑树的阈值,在存储数据时,当链表长度>该值时,则将链表转换成红黑树static final int UN TREE IFY_ TH RESH OLD=6;//桶的链表还原阈值:即红黑树转为链表的阈值, 当在扩容 (resi ze())时(此时Hash Map的数据存储位置 会重 新计算),在重新计算存储位置后,当原有的红黑树内数量<6时,则将 红黑树转换成链表

(3)构造器
public HashMap(){
this.loadFactor = DEFAULT_LOAD_FACTOR;
}

负载因子就是用于控制hash表中所允许存储的元素个数占总容积的百分比。值 越大hash碰撞的概率越高,但是越节约空间;值越小hash碰撞的概率越低,但是越浪费空间;控制容器中允许存放的元素个数上限为 [容积*负载因子]

(4)HashMap的存储结构
Hash Map采用的是拉链法实现数据的存储,其中有一个数组Node [],每个元素上存储一个链表Node。每个Node []数组中的元素被称一个桶bucket,一个桶对应一个hash映射的值, 例如0,1等,可能会出现不同的key,但是hash映射 的位置 相同,例如16、32等,这采用单向链表结构存储hash映射 值相同的所有数据(JDK8+在单个链表 长度 大于 阈值8时自动转换为红黑树,删除节点使某单个树节点 数小于 阈值6时会 自动 从红黑树退化为链表结构)

相关参数:
capacity:当前 数组容量 ,始终 保持2^n,可以 扩容 ,扩容后 数组大小为 当前 的 2倍。
load Factor:负载因子,取值在(0,1)之间,默认为 0. 75
threshold:扩容的阈值,等于 capacity * load Factor

HashMap底层采用的是Entry数组和链表实现。
Map 主要用于存储键key值value对,根据键得到值,因此键不允许重复,但允许值重复。

Hash Map是一个最常用的Map,它 根据键的hashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。

如何判断环型链?

Java7中使用 Entry 来代表 每个 Hash Map 中的数据节点 ,Java8中使用 Node,基 本没有区别 ,都是 key,value,hash 和 next 这四 个属性,不 过,Node 只能用于链表的情况,红黑树的情况需要使用 Tree Node。TREE IFY_ TH RESH OLD为8,如果 新插入的值是链表中的第9个会 触发 下面的treeify Bin(树化操作,就是将单向链转换为红黑树),也就是将链表转换为红黑树。JDK8+插入数据到链表的最后面,Java7是插入到链表的最前面。

(5)HashMap是怎么解决哈希冲突的

在Java中,保存数据有两种比较简单的数据结构:数组和链表。
数组的特点是:寻址容易,插入和删除困难;
链表的 特点 是:寻址困难,但插入和删除容易;
所以将数组和链表结合在一起,发挥两者各自的优势,使用一种叫做链地址法的方式可以解决哈希冲突
这样 就可以将拥有相同哈希值的对象组织 成一个链表放在hash值所对应的bucket下,但 相 比 于hashCode返 回 的int类 型 ,我 们Hash Map初 始 的 容 量 大 小DEFAULT_INI TIAL _CA PAC ITY= 1 << 4(即2的四次 方16)要 远小于int类型的 范围 ,所以 我们 如果只是单纯 的用hashCode取余 来获取 对应的bucket这将会大大增加哈希 碰撞的概率,并 且最坏情况 下还会将Hash Map变成一个 单链表,所以我们 还需要对hashCode作一定的优化主要是因为如果使用hashCode取余,那么相当于参与运 算的只有hashCode的低位,高位是没有起到任何 作用的,所以思路就是让hashCode取值出的高位也参与运 算,进一步降低hash碰撞的概率,使得数据分布更平均,我们把这样的操作称为扰动这比在JDK 1. 7中,更为简洁 ,相比在1. 7中的4次位运 算,5次异或运算(9次扰动),在1. 8中,只进行了1次位运算和1次异或运算(2次扰动)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值