Map的实现

HashMap

前提

二叉树的定义:每个节点最多有两个“叉”,分别是左子节点和右子节点。不要求每个节点都有两个子节点,有的节点只有左子节点,有的节点只有右子节点,并且二叉树的每个节点的左子树和右子树也分别满足二叉树的定义。

二叉搜索树(BST,Binary Search Tree)又名二叉查找树,有序二叉树。树中的任意一个节点,它的左子树中每个节点的值都要小于这个节点的值,而右子树节点的值都大于这个节点的值。在极端情况下会退化为链表,左右子树极度不平衡,查找元素的时间复杂度为O(n),正常情况下O(logN)

红黑树:一种自平衡的二叉搜索树

【HashMap中最重要的数据结构】散列表:红黑树+链表

散列表(Hash Table)又称为哈希表,是根据Key直接访问在内存存储位置value,它是由数组演化而来的,利用了数组支持按照下标进行随机访问数据的特性。

散列冲突,又称为哈希冲突、哈希碰撞。指多个key映射到同一个数组下标位置。

我们通常采用拉链法:数组的每个下标位置称之为桶bucket,每个桶会对应一个链表,当hash冲突后的元素都放到相同槽位对应的链表中或红黑树中。

HashMap的实现原理?

计算key的值通过hashCode()方法,判断两个key是否相同则通过equals()方法。

底层使用hash表数据结构,即数组+(链表 | 红黑树),在添加数据时,计算key的值确认元素在数组中的下标:
key相同则直接替换,不同则存入链表或红黑树中。

Jdk1.7和1.8的区别?

JDK1.7之前采用的是拉链法,数组+ 链表。

JDK1.8及之后采用数组+链表+红黑树,链表长度大于等于8且数组长度大于等于64,则从链表转化为红黑树。

同时1.7采用的是头插法,当发生哈希碰撞的时候,新的元素会被插入到与该哈希值相对应的哈希桶的头部,这种方法插入效率高,但在多线程环境下可能会导致一些问题。

1.8采用的是尾插法,并且如果链表长度超过某个阈值(默认为8),链表会被转换为红黑树,新元素会被插入到红黑树中。这种改变时为了在高并发情况下减少扩容时链表元素原有的顺序,从而在扩容时减少元素的移动嘛。


JDK1.7的put方法,如果定位到的数组没元素则直接插入,如果有元素,则遍历当前元素为头结点的链表,依次和插入的key比较【通过equals方法】,如果相同则直接覆盖,不同则采用头插法。

public V put(K key, V value)
    if (table == EMPTY_TABLE) {
    inflateTable(threshold);
}
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key);
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) { // 先遍历
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    modCount++;
    addEntry(hash, key, value, i);  // 再插入
    return null;
}

JDK1.8

如果定位到的数组位置没有元素 就直接插入。

如果定位到的数组位置有元素就和要插入的 key 比较,如果 key 相同就直接覆盖,如果 key 不相同,就判断 p 是否是一个树节点,如果是就调用e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value)将元素添加进入。如果不是就遍历链表插入(插入的是链表尾部)。

HashMap和ConcurrentHashMap区别?

HashMap不是线程安全的。如果多个线程同时访问HashMap,并且至少有一个线程修改了map,则必须外部同步(如添加Synchronized关键字),即如果都是读操作,则没事。

ConcurrentHashMap是线程安全的,内置了分段锁或其他形式的并发控制机制,允许多个线程并发读写,而不需要外部同步。

性能上,ConcurrentHashMap优于同步的HashMap,因为ConcurrentHashMap的锁分段技术减少了锁竞争。

同步机制:如果需要在多线程环境下使用HashMap,因为没有内置同步机制,我们必须通过外部同步来保证线程安全,如Collections.synchronizedMap方法包装HashMap。

ConcurrentHashMap通过内部锁机制,(java8之前是分段锁,8及以后是CAS操作和volatile变量)来实现同步,从而提供了更高的并发性能。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值