JDK8-数据结构-Map以及具体的实现(待更新)

Map

存储一组键值对象,提供key到value的映射。
在这里插入图片描述

实现类

在这里插入图片描述

java.util.EnumMap

key为枚举,value为Object[],使用枚举的特性,将枚举的ordinal属性作为数组的下标。

  • 增加:put(K key, V value)
public V put(K key, V value) {
   
    typeCheck(key);
	// 枚举的ordinal属性是根据定义枚举的顺序生成的,从0开始
    int index = key.ordinal();
    Object oldValue = vals[index];
    vals[index] = maskNull(value);
    if (oldValue == null)
        size++;
    return unmaskNull(oldValue);
}

java.util.HashMap

数据结构与算法

HashMap用到数组,链表(单链表),树(红黑树)三种数据结构和哈希算法。

  • 数组:数组的内存是连续型的,所以根据下标可以算出内存地址。

例如:int[10]分配的地址为1000到1039,int[i]=1000(首地址)+i*4

  • 哈希算法:将Map中的key经过hash函数进行运算之后,让其通过key,可以直接算出下标,实现通过key达到O(1)的性能
static final int hash(Object key) {
   
    int h;
    // 异或运算:0^0=0;0^1=1;1^0=1;1^1=0
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

// 与运算:0&0=0;0&1=0;1&0=0;1&1=1
// 下标计算方法,将数组长度和hash值进行与运算,可以保证下标不会越界
int index = ( size - 1) & hash(key)
  • 单链表
  • 红黑树

当key发生hash冲突时,就需要使用到单链表,当链表达到一定长度时会转为红黑树,来提升查询效率;当红黑树的节点在指定范围时会转为单链表,具体如下图:

在这里插入图片描述

源码阅读

属性
  • loadFactor:负载因子,用于计算临界值(threshold)。默认为0.75
  • threshold:临界值,用于判断是否要扩容。计算公式为size*loadFactor
  • TREEIFY_THRESHOLD:转红黑树临界值常量,值为8。判断是否树化的条件之一。
  • UNTREEIFY_THRESHOLD:转链表临界值常量,值为6。转为链表的情况之一。
  • MIN_TREEIFY_CAPACITY:转红黑树容量最小值常量,值为64。判断是否树化的条件之一
方法
  • 增加:put(K key, V value)
public V put(K key, V value) {
   
    return putVal(hash(key), key, value, false, true);
}

// 时间复杂度:O(logn)
// 数组O(1)
// 如果是单链表,则为O(n),但是这个n最大为8,也可以算是O(1)
// 如果是红黑树,则为O(logn)
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
   
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    if ((p = tab[i = (n - 1) & hash]) == null) // 不存在hash冲突
        tab[i] = newNode(hash, key, value, null);
    else {
    // hash冲突
        Node<K,V> e; K k;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k)))) // 同一个元素
            e = p;
        else if (p instanceof TreeNode) // 当前节点为树节点,使用红黑树的插入
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
    // 插入到链表中
            for (int binCount = 0; ; ++binCount) {
   
                if ((e = p.next) == null) {
    // 追加在链表的尾部
                    p.next = newNode(hash, key, value, null)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

瑾析编程

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

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

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

打赏作者

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

抵扣说明:

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

余额充值