LinkedHashMap简介及部分源码分析

概述

LinkedHashMap实现了Map接口,即允许放入key为null的元素,也允许插入value为null的元素。从名字上可以看出该容器是LinkedListHashMap的混合体,也就是说它同时满足HashMapLinkedList的某些特性。可将LinkedHashMap看作采用LinkedList增强的HashMap

特点

  • LinkedHashMap LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成
  • LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序
  • 由于继承自HashMap,所以依旧是线程不安全的

出于性能原因,_LinkedHashMap_是非同步的(not synchronized),如果需要在多线程环境使用,需要手动同步;或者通过如下方式将_LinkedHashMap_包装成(wrapped)同步的:
Map m = Collections.synchronizedMap(new LinkedHashMap(...));

  • Collections.synchronizedMap 如何实现 Map 线程安全?
  • 基于 Synchronized ,实际上就是锁住了当前传入的 Map 对象。

LinkedHashMapHashMap的直接子类,二者唯一的区别是LinkedHashMapHashMap的基础上,采用双向链表的形式将所有entry连接起来,主体部分跟_HashMap_完全一样,多了header指向双向链表的头部(是一个哑元),该双向链表的迭代顺序就是entry的插入顺序,这样是为保证元素的迭代顺序跟插入顺序相同。bdea22a2-4a2c-436a-8225-3dd059e1e8b4.png

方法分析

构造函数

public LinkedHashMap() {
    //调用父类的构造器使用默认容量16与默认负载因子0.75
        super();
        accessOrder = false;
    }

public LinkedHashMap(int initialCapacity) {
    //调用父类的构造器设置初始大小和使用默认负载因子0.75
        super(initialCapacity);
        accessOrder = false;
    }

public LinkedHashMap(int initialCapacity, float loadFactor) {
        //调用父类构造器设置初始大小和负载因子,
      super(initialCapacity, loadFactor);
        accessOrder = false;
    }

public LinkedHashMap(int initialCapacity, float loadFactor,boolean accessOrder) {
      //调用父类构造器设置初始大小和负载因子
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

//将集合m中的元素拷贝到当前LinkedHashMap中
public LinkedHashMap(Map<? extends K, ? extends V> m) {
        super();
        accessOrder = false;
        putMapEntries(m, false);
    }

get(K key)

get(Object key)方法根据指定的key值返回对应的value。该方法跟HashMap.get()方法的流程几乎完全一样

HashMap

put(K key, V value)方法是将指定的key, value对添加到map里。
该方法首先会对map做一次查找,看是否包含该元组,如果已经包含则直接返回,查找过程类似于get()方法;如果没有找到,则会通过addEntry(int hash, K key, V value, int bucketIndex)方法插入新的entry。

注意,这里的插入有两重含义:

  1. 从table的角度看,新的entry需要插入到对应的bucket里,当有哈希冲突时,采用头插法将新的entry插入到冲突链表的头部。
  2. 从header的角度看,新的entry需要插入到双向链表的尾部。

remove()

remove(Object key)的作用是删除key值对应的entry,该方法的具体逻辑是在removeEntryForKey(Object key)里实现的。removeEntryForKey()方法会首先找到key值对应的entry,然后删除该entry(修改链表的相应引用)。查找过程跟get()方法类似。

注意,这里的删除也有两重含义:

  1. 从table的角度看,需要将该entry从对应的bucket里删除,如果对应的冲突链表不空,需要修改冲突链表的相应引用。
  2. 从header的角度来看,需要将该entry从双向链表中删除,同时修改链表中前面以及后面元素的相应引用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值