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次扰动)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值