你不知道的Map家族中的那些冷门容器

Java中的常见五种map容器源码分析总结(HashMap、Hashtable、ConcurrentHashMap、LinkedHashMap、TreeMap   断断续续写了半个月,今天终于把TreeMap容器中的红黑树搞定了,现在来水一篇又快又短的Java Map容器总结博客 ????????。 注明:本篇博客会涉及容器的源码什么的,主要是总结各个map容器的底层实现特点、主要运用场景。如果你需要详细了解更多关于Java中的map容器实现的细节,文末会提供我前面写的源码分析的博客链接,欢迎阅读。 Java中的常见五种map容器源码分析总结目录一、`Java`中... 阅读详情

概述

本篇文章主要讲解下Map家族中3个相对冷门的容器,分别是WeakHashMap、EnumMap、IdentityHashMap, 想必大家在平时的工作中也很少用到,或者压根不知道他们的特性以及适用场景,本篇文章就带你一探究竟。

WeakHashMap

介绍

WeakHashMap称为弱三列映射,实现了Map接口,具有如下特性:

  • WeakHashMap中的entry是一个弱引用,当除了自身有对key的引用外,此key没有其他引用,那么GC之后此map会自动丢弃此值。
  • 不是线程安全的
  • 可以存储null

演示案例

public static void main(String[] args) {
        String a = new String("a");
        String b = new String("b");
        Map weakmap = new WeakHashMap();
        weakmap.put(a, "aaa");
        weakmap.put(b, "bbb");
        a = null;
        b = null;
        // 进行gc
        System.gc();
        Iterator j = weakmap.entrySet().iterator();
        while (j.hasNext()) {
            Map.Entry en = (Map.Entry) j.next();
            System.out.println("weakmap:" + en.getKey() + ":" + en.getValue());
        }
    }
复制代码

运行结果:

已经被gc回收了。

原理实现

从这里我们可以看到其内部的Entry继承了WeakReference,也就是弱引用,所以就具有了弱引用的特点。

弱引用的特点是在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

WeakReference中有个成员变量ReferenceQueue,他的作用是GC会清理掉对象之后,引用对象会被放到ReferenceQueue中,然后遍历这个queue进行删除即可Entry。WeakHashMap内部有一个expungeStaleEntries函数,在这个函数内部实现移除其内部不用的entry从而达到的自动释放内存的目的。因此我们每次访问WeakHashMap的时候,都会调用这个expungeStaleEntries函数清理一遍。

使用场景

在如今的并发泛滥的大环境下,大家应该都用过缓存,缓存都是放在内存中的,而内存几乎是计算机中最宝贵也是最稀缺的资源,所以需要谨慎的使用,不然很容易就出现 OOM。缓存的主要作用是为了更快的处理业务、降低服务器的压力,那么就要保证缓存命中率,这里假设整个缓存是一个 key-value 结构的(以键值对缓存为例),HashMap 作为强引用对象在没有主动将 key 删除时是不会被 JVM 回收的,这样 HashMap 中的对象就会越积越多直到 OOM 错误;那么如何做到既让缓存的命中率高又不占用那么多的内存,这里就可以采用 WeakHashMap,当然不会有 HashMap 100% 的命中率(假设内存足够),但是在保证程序正常的前提下更好的实现了缓存这套解决方案。

EnumMap

介绍

用于枚举类型键的专用Map实现。枚举映射中的所有键必须来自创建映射时显式或隐式指定的单个枚举类型。

相对于HashMap中枚举作为key, EnumMap内部以一个非常紧凑的数组存储value,并且根据enum类型的key直接定位到内部数组的索引,并不需要计算hashCode(),不但效率最高,而且没有额外的空间浪费。

  • 不是线程安全的
  • 可以存放null值

演示案例

public static void main(String[] args) {
        // 构造函数传入类型
        Map<DayOfWeek, String> map = new EnumMap<>(DayOfWeek.class);
        map.put(DayOfWeek.MONDAY, "星期一");
        map.put(DayOfWeek.TUESDAY, "星期二");
        map.put(DayOfWeek.WEDNESDAY, "星期三");
        map.put(DayOfWeek.THURSDAY, "星期四");
        map.put(DayOfWeek.FRIDAY, "星期五");
        map.put(DayOfWeek.SATURDAY, "星期六");
        map.put(DayOfWeek.SUNDAY, "星期日");
        System.out.println(map);
        System.out.println(map.get(DayOfWeek.MONDAY));
    }

    enum DayOfWeek {
        MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
    }
复制代码

原理实现

put方法源码如下:

public V put(K key, V value) {
        // 对枚举类型进行检查,看key和构造函数传入的class类型是否一致
        typeCheck(key);
        // 枚举的顺序
        int index = key.ordinal();
        // 原来位置的值
        Object oldValue = vals[index];
        // 设置值
        vals[index] = maskNull(value);
        if (oldValue == null)
            size++;
        return unmaskNull(oldValue);
    }
复制代码

通过put源码发现是通过数组的方式实现存储,而且也不需要进行扩容。

使用场景

如果项目中遇到针对枚举作为key的映射容器,可以优先选择EnumMap。

IdentityHashMap

介绍

该类使用散列表实现Map接口,在比较键(和值)时使用引用相等代替对象相等。换句话说,在一个IdentityHashMap中,当且仅当(k1==k2)两个键k1和k2被认为是相等的。(在正常的Map实现(如HashMap)两个键k1和k2被认为是相等的,当且仅当(k1==null ?k2 = = null: k1.equals (k2)))。

  • 不是线程安全的
  • 无序
  • key不可以是null

演示案例

public static void main(String[] args) {
        // hashMap
        Map<Integer, String> hashMap = new HashMap<>();
        // identityHashMap
        Map<Integer, String> identityHashMap = new IdentityHashMap<>();

        hashMap.put(new Integer(200), "a");
        hashMap.put(new Integer(200), "b");
        identityHashMap.put(new Integer(200), "a");
        identityHashMap.put(new Integer(200), "b");

        //遍历hashmap
        System.out.println("hashmap 结果:");
        hashMap.forEach((key, value) -> {
            System.out.println("key = " + key + ", value = " + value);
        });

        //遍历hashmap
        System.out.println("identityHashMap 结果:");
        identityHashMap.forEach((key, value) -> {
            System.out.println("key = " + key + ", value = " + value);
        });

    }
复制代码

运行结果:

原理实现

IdentityHashMap底层的数据结构就是数组,我们关注下put方法:

调用hash方法,获取key在table的位置index,然后进行赋值操作,也是分成了3种情况:

1.item == k,找到了对应的key,value存在key右相邻的位置,对tab[i + 1]进行更新,并返回原来的值;

2.item == null,表示table中没有对应的key值,跳出for循环,执行tab[i] = k和tab[i + 1] = value进行新key的插入操作。个人觉得这里的扩容时机选择的不太好,好不容易找到的更新位置,因为扩容给整没了,还得再次重新计算,可以和HashMap一样,在更新后再扩容。

3.item != null && item != key,表示hash冲突发生,调用nextKeyIndex获取处理冲突后的index位置,然后重复上面的过程。

我们再来看下hash方法:

IdentityHashMap中获取hash值采用的System.identityHashCode方法,在不重写Object.hashCode方法时,System.identityHashCode和Object.hashCode返回的值相同,相当于对象的唯一的HashCode。System.identityHashCode(null)始终返回0, 无论是否重写Object.hashCode,都不影响System.identityHashCode的执行结果。

使用场景

当我们必须使用地址相等来判断值相等的场合,以及我们确定只要其地址不相等,则其equals方法的结果也必定不相等的场合。

总结

本文主要讲解了集中不常用的Map, 当然我们也需要了解他们的特性,在有些时候还是会用到的。

并发中的Map容器 本文作者:王一飞,叩丁狼高级讲师。原创文章,转载请注明出处。   上几篇讨论了并发环境下list容器的操作, 本篇我们来聊下另外一个集合容器:Map 家族体系 Map:以key-value对的形式存在,一种数据结构,一个key, 映射一个value值, map能包含重复的key值, 一个key最多只能映射到一个值。 常用方法有: 添加: V put(K key, V value); 删除... 阅读详情

相关推荐

集合系列(七) -WeakHashMap详解

本文主要从数据结构和算法层面,探讨 WeakHashMap 的实现。

程序员志哥的博客 1454

java WeakHashMap详细介绍(源码解析)和使用示例

概要 这一章,我们对WeakHashMap进行学习。 我们先对WeakHashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用WeakHashMap。 第1部分 WeakHashMap介绍 第2部分 WeakHashMap数据结构 第3部分 WeakHashMap源码解析(基于JDK1.6.0_45) 第4部分 WeakHashMap遍历方式 第5部分 WeakH

Code-lover's Learning Notes 1456

微信小程序 “net::ERR_CONNECTION_REFUSED” 报错大揭秘与破解之道

在微信小程序开发与运行过程中,“net::ERR_CONNECTION_REFUSED” 报错是开发者常遇难题。该错误意味着小程序与服务器连接建立失败,会导致功能无法使用、数据加载异常等问题,严重影响用户体验和业务运转。本文系统剖析此错误,从网络环境佳、服务器异常、小程序配置有误等常见触发场景入手,提供网络、服务器、配置、代码等多维度排查步骤,给出针对性解决策略,如修复网络、处理服务器故障、修正配置与代码错误,还提出开发与运维阶段的预防措施,助力开发者高效解决该报错问题。

邓邓子的博客 5998

10.Java 集合 - WeakHashMap

基本概念首先来看它的继承关系: WeakHashMap 是以弱键实现的基于哈希表的 Map。在 WeakHashMap 中,当某个键再正常使用时,将自动移除其条目。更精确地说,对于一个给定的键,其映射的存在并阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。丢弃某个键时,其条目从映射中有效地移除,因此,该类的行为与其他的 Map 实现有所同。 需要注意的地方: nu

一把空心菜 927

Java集合-----WeakHashMap

文章目录Java四大引用强引用软引用弱引用虚引用WeakHashMap概述expungeStaleEntries() Java四大引用       在介绍WeakHashMap前,我们先来介绍一下Java中的四大引用。       Java四大引用分别为:强引用、软引用、弱引用、虚引用。       它们的作用分别是:灵活的控制对

Colorful_X的博客 421

一文搞定WeakHashMap

在缓存场景下,由于内存是有限的,能缓存所有对象,因此就需要一定的删除机制,淘汰掉一些对象。这个时候可能很快就想到了各种Cache数据过期策略,目前也有一些优秀的包提供了功能丰富的Cache,比如Google的,它支持数据定期过期、LRU、LFU等策略,但它仍然有可能会导致有用的数据被淘汰,没用的数据迟迟淘汰(如果策略使用得当的情况下这都是小概率事件)。现在有种机制,可以让Cache里用的key数据自动清理掉,用的还留着,会出现误删除。

SevenCoding的博客 889

WeakHashMap原理

WeakHashMap 中key在没有强引用的时候,如果发送了gc,该key就会被回收。为了保证一致性,该Map中回收方法为expungeStaleEntries。以上代码会遍历引用队列,然后删除已被回收的键值对。该方法会在getTable(获取表),size(获取表大学)、resize(扩容)的时候使用。因此,expungeStaleEntries方法会在WeakHashMap增删改查、扩容的地方调用。而getTable会在增删改查的时候调用。

shaui058的博客 200

Java中的Map家族概要

前文介绍Java容器的框架时谈到了容器主要分为Collection和Map浅谈Java容器从文中配图就可以看出Map容器中非常特殊。我们今天大致了解了Map的基本概念和他的几个主要实现类,后面会逐个介绍这些实现类。其中的HashMap是最最最最重要的。

Luisa2016的博客 1665

map对象建立家族姓氏查询

题目:定义一个map对象,其元素的键是家族姓氏,而值是存储该家族孩子名字的vector对象。为这个map容器输入至少六个条目。通过基于家族姓氏的查询检测你的程序,查询应输出该家族所有孩子的名字。   //定义一个map对象,其元素的键是家族姓氏 //而值则是存储该家族孩子名字的vector对象 //进行基于家族姓氏的查询,输出该家族所有孩子的名字 #include&lt;iostr...

weixin_33980459的博客 308

java 容器_java中的容器家族成员

前言今天打算跟大家聊一聊java中的容器,这个话题很大,可以从数据结构来讲,可以从线程安全方面来讲,可以从效率来讲,我思考了半天,小编公众号的名字是《杂讲java》,那我就杂讲吧(皮一下),想到哪里说到哪里,从大的方面来分,java容器分为两部分,Map和Conllection,Conllection又分为List、Set以及Queue,接下来喝杯茶水的功夫,简单唠一唠java容器家族成员们。...

weixin_39610956的博客 118

Java 容器Map

Java 容器Map Map 简介 Map 架构 Map 家族主要成员功能如下: MapMap 容器家族的祖先,Map 是一个用于保存键值对(key-value)的接口。Map能包含重复的键;每个键最多只能映射到一个值。 AbstractMap 继承了 Map 的抽象类,它实现了 Map 中的核心 API。其它 Map 的实现类可以通过继承AbstractMap 来减少重复编码。 SortedMap 继承了 Map 的接口。SortedMap中的内容是排序的键值对,排序的方法是通

云想的博客 232

WeakHashMap垃圾回收原理

介绍WeakHashMap自然联想到的是HashMap。确实,WeakHashMap与HashMap一样是个散列表,存储内容也是键值对。与HashMap类似的功能就展开了,本文重点关注在WeakHashMap是如何做到回收数据?垃圾回收原理谈WeakHashMap回收原理得从WeakReference(弱引用)说起。大家都知道GC回收对象前提是,从根集出发的引用中没有有效引用指向该对象,则该对象...

hellozhxy的博客 1118

Java集合之WeakHashMapIdentityHashMap、EnumMap介绍

WeakHashMapWeakHashMap与HashMap的用法基本类似。区别: HashMap的key保留了对实际对象的强引用,这意味着只要HashMap对象被销毁,还HashMap的所有key所引用的对象就会被垃圾回收,HashMap会自动删除这些key所对应的key-value对; WeakHashMap的key只保留对实际对象的弱引用,这意味着如果WeakHashMap对象的key

桉树先生 3100

java集合-WeakHashMap(五)

Date: 2017-01-14 10:10:12 java集合-WeakHashMap与ThreadLocal(五) 前面两篇文章《HashMap源码分析》,《Java基础-强,弱,软引用》已经把WeakHashMap用到的技术都讲完了。这篇文章也就没啥好讲的了。 WeakHashMap就是一个HashMap,只过它的key继承了WeakReference表示key是一个弱引用,在G...

piaoslowly的专栏 1739

java学习笔记之WeakHashMapIdentityHashMap、EnumMap

WeakHashMap中的key是弱引用。(弱引用是指一旦GC运行,就会立刻回收,该引用所指的对象) 例子: “`java /** WeakHashMap 中的key为弱引用,GC(Garbage Collection) 一旦运行就会立即回收 @author ly1 * */ public class TestWeakHashMap { public static vo

小白进阶的博客 523

WeakHashMap的一些理解

WeakHashMap在GC的时候会清除未被强引用的键值,接下来便分析一下是如何做到的。首先看一下其内部Entry对象的结构,Entry继承了WeakReference,从Entry的构造函数可以知道,在put一个key-value时,key作为一个弱引用而存在,getKey()也是返回这个key的引用,这里可以看到unmaskNull的作用是对应于put了一个null的key,当put的key为...

kimichen123的专栏 762

Windows6.1-KB963697-x64.msu.7z

Windows6.1-KB963697-x64.msu由于windows service 2008_r2系统自带流媒体服务器,需要安装第三方程序包。

上一篇: PySpark 数据分析基础:PySpark 原理详解
下一篇: SpringBoot与Thymeleaf模板入门整合篇
java小姜在线冲
博客等级 码龄4年 51粉丝 137原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值