当前位置: 首页 > 编程日记 > 正文

Java集合框架:EnumMap

EnumMap定义

package java.util;import java.util.Map.Entry;
import sun.misc.SharedSecrets;
public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>implements java.io.Serializable, Cloneable{private final Class<K> keyType;private transient K[] keyUniverse;private transient Object[] vals;private transient int size = 0;
}

keyType变量是EnumMap的key泛型的类对象,EnumMap依据这个类型。能够获得keyUniverse的内容。vals存放的是与keyUniverse映射的值。假设没有映射则为null,假设映射为null则会特殊处理成NULL。NULL的定义例如以下:

 private static final Object NULL = new Object() {public int hashCode() {return 0;}public String toString() {return "java.util.EnumMap.NULL";}};

对于值NULL的处理相似WeakHashMap的特殊处理,会有两个方法:

    private Object maskNull(Object value) {return (value == null ? NULL : value);}private V unmaskNull(Object value) {return (V) (value == NULL ? null : value);}

这样能够区分vals中是null(即没有映射)还是NULL(即映射为null);
  EnumMap的size是依据vals中的非null(包含NULL)的值的个数确定的,比方put方法:

    public V put(K key, V value) {typeCheck(key);int index = key.ordinal();Object oldValue = vals[index];vals[index] = maskNull(value);if (oldValue == null)size++;return unmaskNull(oldValue);}

typeCheck推断key的类对象或者父类对象是否与keyType相等,假设不相等则抛出ClassCastException异常。
  注意EnumMap并没有相似HashMap的resize的过程,也没有载入因子的概念,由于在一个EnumMap创建的时候,keyUniverse和vals的大小就固定。


EnumMap使用

先举个小样例:

package collections.map;import java.util.EnumMap;
import java.util.Map;public class EnumMapTest
{public enum Color{RED,BLUE,BLACK,YELLOW,GREEN;}public static void main(String[] args){EnumMap<Color,String> map = new EnumMap<>(Color.class);EnumMap<Color,String> map = new EnumMap<>(Color.class);map.put(Color.YELLOW, "黄色");map.put(Color.RED, "红色");map.put(Color.BLUE, null);
//        map.put(null, "无");   //会报NullPonitException的错误map.put(Color.BLACK, "黑色");map.put(Color.GREEN, "绿色");for(Map.Entry<Color,String> entry:map.entrySet()){System.out.println(entry.getKey()+":"+entry.getValue());}System.out.println(map);}
}

执行结果:

RED:红色
BLUE:null
BLACK:黑色
YELLOW:黄色
GREEN:绿色
{RED=红色, BLUE=null, BLACK=黑色, YELLOW=黄色, GREEN=绿色}

EnumMap的key不同意为null,value能够为null,依照key在enum中的顺序进行保存。非线程安全。能够用工具类Collections进行包装成线程安全的:

Map<EnumKey, V> m = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...));

有关enum的应用知识能够參考《Java枚举类型enum》。
  EnumMap的基本操作都比較快,都在常量时间内完毕,基本上(但不保证)比HashMap快。
  EnumMap有三个构造函数:

  • public EnumMap(Class<K> keyType);
  • public EnumMap(EnumMap<K, ?

    extends V> m);

  • public EnumMap(Map<K, ?

    extends V> m) ;

前两个构造函数一目了然,对第三个构造函数进行分析:

Map<Integer,Integer> map1 = new HashMap<>();map1.put(1, 1);map1.put(3, 3);map1.put(2, 2);Map<Integer,Integer> map2 = new EnumMap<>(map1);//编译器提示错误:Cannot infer type arguments for EnumMap<>

这个是由于Integer并非extends Enum;
  这里变换一下,採用Map

Map<Enum,Integer> map1 = new HashMap<>();map1.put(Color.YELLOW, 1);map1.put(Color.RED, 3);map1.put(Color.BLUE, 2);Map<Enum,Integer> map2 = new EnumMap<>(map1);for(Map.Entry entry:map2.entrySet()){System.out.println(entry.getKey()+":"+entry.getValue());}System.out.println(map2);System.out.println(map2.size());

能够正常执行。输出结果:

RED:3
BLUE:2
YELLOW:1
{RED=3, BLUE=2, YELLOW=1}
3

相信大家能够总结个一二了吧。


EnumMap用途

《Effective Java》中作者建议用EnumMap取代叙述索引。最好不要用序数来索引数组,而要使用EnumMap
  这里採用《Effective Java》书中的样例来举例。

     public static class Herb{public enum Type{ANNUAL, PERENNIAL, BIENNTAL}private final String name;private final Type type;public Herb(String name, Type type){this.name = name;this.type = type;}public Type getType(){return type;}@Overridepublic String toString(){return name;}}

如今用一座种满香草的花园,想要依照类型(一年生、多年生、两年生,即上面Type的类型)进行组织之后将这些植物列出来。假设使用数组实现的话。须要构建三个集合,每种类型一个。而且遍历整座花园,将每种香草放到相应的集合中。

Herb[] garden = new Herb[]{new Herb("f1",Herb.Type.ANNUAL),new Herb("f2",Herb.Type.PERENNIAL),new Herb("f3",Herb.Type.BIENNTAL),new Herb("f4",Herb.Type.PERENNIAL),new Herb("f5",Herb.Type.ANNUAL),new Herb("f6",Herb.Type.BIENNTAL),new Herb("f7",Herb.Type.ANNUAL),new Herb("f8",Herb.Type.BIENNTAL),new Herb("f9",Herb.Type.PERENNIAL)};Set<Herb>[] herbsByType = (Set<Herb>[]) new Set[Herb.Type.values().length];for(int i=0;i<herbsByType.length;i++){herbsByType[i] = new HashSet<Herb>();}for(Herb h:garden){herbsByType[h.type.ordinal()].add(h);}for(int i=0;i<herbsByType.length;i++){System.out.printf("%s:%s%n", Herb.Type.values()[i],herbsByType[i]);}

执行结果:

ANNUAL:[f5, f7, f1]
PERENNIAL:[f4, f2, f9]
BIENNTAL:[f8, f3, f6]

这样的方法确实可行。可是影藏着很多问题。由于数组不能和泛型兼容。程序须要进行未受检的转换,而且不能正确无误地进行编译。由于数组不知道它的索引代表着什么,你必须手工标注这些索引的输出。可是这样的方法最严重的问题在于。当你訪问一个依照枚举的叙述进行索引的数组时,使用正确的int值就是你的职责了。int不能提供枚举的类型安全。
  可是你能够用EnumMap改善这个程序:

Herb[] garden = new Herb[]{new Herb("f1",Herb.Type.ANNUAL),new Herb("f2",Herb.Type.PERENNIAL),new Herb("f3",Herb.Type.BIENNTAL),new Herb("f4",Herb.Type.PERENNIAL),new Herb("f5",Herb.Type.ANNUAL),new Herb("f6",Herb.Type.BIENNTAL),new Herb("f7",Herb.Type.ANNUAL),new Herb("f8",Herb.Type.BIENNTAL),new Herb("f9",Herb.Type.PERENNIAL)};Map<Herb.Type, Set<Herb>> herbsByType = new EnumMap<>(Herb.Type.class);for(Herb.Type t : Herb.Type.values()){herbsByType.put(t, new HashSet<Herb>());}for(Herb h:garden){herbsByType.get(h.type).add(h);}System.out.println(herbsByType);

执行结果:

{ANNUAL=[f7, f1, f5], PERENNIAL=[f4, f2, f9], BIENNTAL=[f8, f6, f3]}

这段程序更剪短、更清楚,也更安全。执行速度方面能够与使用序数的数组相媲美。注意EnumMap构造器採用键类型的Class对象:这是一个有限制的类型令牌,它提供了执行时的泛型信息


总结

EnumMap是专门为枚举类型量身定做的Map实现。

尽管使用其他的Map实现(如HashMap)也能完毕枚举类型实例到值得映射,可是使用EnumMap会更加高效:它仅仅能接收同一枚举类型的实例作为键值。而且由于枚举类型实例的数量相对固定而且有限,所以EnumMap使用数组来存放与枚举类型相应的值。这使得EnumMap的效率很高。EnumMap在内部使用枚举类型的ordinal()得到当前实例的声明次序,并使用这个次序维护枚举类型实例相应值在数组的位置。


參考资料:
1. 《Java枚举类型enum》
2. 《Effective Java(Second Edition)》. Joshua Bloch.
3. 《EnumMap与Enumset的使用 》

转载于:https://www.cnblogs.com/yangykaifa/p/7388563.html

相关文章:

javascript eval和JSON之间的联系

eval函数的工作原理 eval函数会评估一个给定的含有JavaScript代码的字符串&#xff0c;并且试图去执行包含在字符串里的表达式或者一系列的合法的JavaScript语句。eval函数将把最后一个表达式或者语句所包含的值或引用作为返回值。 举例说明 eval评估JavaScript表达式var bar …

notification antd 弹窗使用示例

示例代码 import { notification } from antd;notification.error({description: 您的网络发生异常&#xff0c;无法连接服务器,message: 网络异常,});

python如何编写数据库_如何在几分钟内用Python编写一个简单的玩具数据库

python如何编写数据库MySQL, PostgreSQL, Oracle, Redis, and many more, you just name it — databases are a really important piece of technology in the progress of human civilization. Today we can see how valuable data are, and so keeping them safe and stable…

齐博cms 7.0 漏洞分析

** 0x01 原理分析 ** 还是很早之前爆出来的漏洞&#xff0c;现在拿出来学习一下&#xff0c;参考阿里巴巴&#xff1a;https://security.alibaba.com/... 漏洞发生在/inc/common.inc.php页面中。首先看这个函数&#xff1a; 首先使用ini_get来获取php.ini中变量register_global…

J2EE 中的服务器 tomcat6.0 配置

Tomcat6.0 配置 第一步&#xff1a;下载jdk和tomcat&#xff1a;JDK下载 Tomcat下载 最新的jdk为1.6.10&#xff0c;tomcat为6.0&#xff0c;建议jdk1.4以上&#xff0c;tomcat4.0以上 第二步&#xff1a;安装和配置你的jdk和tomcat&#xff1a;执行jdk和tomcat的安装程序…

【Ant Design Pro 四】react 点击事件传参

简单的绑定点击事件传参&#xff1a; 点击事件 function myClick(){console.log(点击)}return (<Button onClick{myClick}>点击</Button>) 点击事件传参 sendGoods(e){console.log(sendGoods,e)}render() {retrun(<Button type"primary" onClick{(e…

初创公司为什么要我_在一家大型初创公司担任副总裁之前,我希望知道什么

初创公司为什么要我by Assaf Elovic通过阿萨夫埃洛维奇 在一家大型初创公司担任副总裁之前&#xff0c;我希望知道什么 (What I wish I knew before becoming a VP at a large startup) When I started my position as VP of R&D at a growing startup, I thought my bigg…

微信小程序自定义轮播图滚动样式 自定义组件轮播图的实现

效果图&#xff1a; 实现代码&#xff1a; wxml <view class"card card_b"><swiper autoplay"{{true}}" interval"4000" duration"500" current"{{swiperCurrent}}" bindchange"swiperChange" class&qu…

好看的dialog,sweet Alert Dialog 导入Android Studio

系统自带的dialog实在是丑到无法忍受。所以找到了一款比較好的第三方dialog。 github 地址例如以下: https://github.com/pedant/sweet-alert-dialog 老规矩&#xff0c;还是先看效果图&#xff01; 以下来介绍导入Android studio的方法 首先将github上的项目clone到本地。然后…

linux系统中删除文件夹

rm -rf 文件夹的名称 rm-r 文件名称转载于:https://www.cnblogs.com/chucklu/p/4890523.html

unity开发入门_Unity游戏开发终极入门指南

unity开发入门Unity is a great tool for prototyping everything from games, to interactive visualisations. In this article, we run through all you need to know to get started using Unity.Unity是一个很好的工具&#xff0c;可用于制作从游戏到交互式可视化等所有内…

uvalive 3218 Find the Border

题意&#xff1a;一条封闭折线将平面分成了若干个区域&#xff0c;按顺序给出折线各点的坐标&#xff0c;要求输出封闭折线的轮廓。 题解&#xff1a;用类似卷包裹的算法&#xff0c;先确定一个一定会被选中的点(x坐标最小&#xff0c;y坐标最小)作为起点&#xff0c;然后把可…

[Mac] mac linux 多线程下载利器 axel

​> 之前做过一些文件下载的统计&#xff0c;发现谷歌浏览器chrome和火狐firefox, 一般都是单线程的下载文件&#xff0c;360浏览器却是多线程的下载。如今切换到了mac上&#xff0c;发现没有360哪个浏览器&#xff0c;就像找个在linux或者mac下能够多线程下载的工具。 linu…

antd 表单提交,文件和表单内容一起提交,表单校验

用很简单的源码实现包含下列 antd 表单相关知识: 1.表单必填校验,规则校验 2.Upload 上传图片,获取上传图片的状态,如上传成功,上传失败,上传进度条,删除上传的文件 3.获取 Input 组件用户输入的值,设置默认值 4.提交表单不刷新页面 5.把上传的图片显示在页面 页面…

代码注释//_您应该停止编写//的五个代码注释,并且//应该开始的一个注释

代码注释//提供来自您最喜欢和最受欢迎的开源项目的示例-React&#xff0c;Angular&#xff0c;PHP&#xff0c;Pandas等&#xff01; (With examples from your favorite and most popular open source projects — React, Angular, PHP, Pandas and more!) 代码质量与注释之间…

eclipse安装maven

maven 下载地址&#xff1a;http://maven.apache.org/download.cgi 1.maven环境配置 将下载的maven解压到某一盘下&#xff0c;进入E:\maven\apache-maven-3.3.9\conf目录&#xff0c;修改setting.xml文件 找到<localRepository>节点&#xff0c;配置本地仓库的地址&…

微信小程序 循迹功能制作

规划地图的路径&#xff0c;实时获取用户当前的定位&#xff0c;进行路线循迹导航功能的开发&#xff1a; 效果图&#xff1a; 实现代码&#xff1a; <map id"map" enable-satellite longitude"{{longitude1}}" latitude"{{latitude1}}" sca…

DOM解析和SAX解析的区别

DOM解析和SAX解析的区别 博客分类&#xff1a; XMLDOM SAX DOM解析和SAX解析的区别 No区 别DOM解析SAX解析1操作将所有文件读取到内存中形成DOM树&#xff0c;如果文件量过大&#xff0c;则无法使用顺序读入所需要的文件内容&#xff0c;不会一次性全部读取&#xff0c;不受文件…

java编写代码用什么_如何学习用Java编写代码:为什么要学习以及从哪里开始

java编写代码用什么by John Selawsky约翰塞劳斯基(John Selawsky) 如何学习用Java编写代码&#xff1a;为什么要学习以及从哪里开始 (How to learn to code in Java: why you should and where to start) Define your career goals and choose a language. This is the most i…

迷宫寻宝(搜索)

迷宫寻宝&#xff08;一&#xff09; 时间限制&#xff1a;1000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;4描述一个叫ACM的寻宝者找到了一个藏宝图&#xff0c;它根据藏宝图找到了一个迷宫&#xff0c;这是一个很特别的迷宫&#xff0c;迷宫里有N个编过号的门&…

理解Python的迭代器(转)

原文地址: http://python.jobbole.com/81916/ 另外一篇文章: http://www.cnblogs.com/kaituorensheng/p/3826911.html 什么是迭代 可以直接作用于for循环的对象统称为可迭代对象(Iterable)。 可以被next()函数调用并不断返回下一个值的对象称为迭代器(Iterator)。 所有的Iterab…

快捷导航动画制作

做了一个仿大众点评的快捷导航动画效果&#xff0c;点击导航内的箭头&#xff0c;导航缩放&#xff0c;点击快捷导航再伸展。 看效果图&#xff1a; 实现代码&#xff1a; <block wx:if"{{!isCustom}}"><view class"home_and_reSource" animati…

instant apps_Android Instant Apps 101:它们是什么以及它们如何工作

instant appsby Tomislav Smrečki通过TomislavSmrečki Android Instant Apps are a cool new way to consume native apps without prior installation. Only parts of the app are downloaded and launched, giving the users a native look and feel in a couple of secon…

数据库分享一: MySQL的Innodb缓存相关优化

无论是对于哪一种数据库来说&#xff0c;缓存技术都是提高数据库性能的关键技术&#xff0c;物理磁盘的访问速度永 远都会与内存的访问速度永远都不是一个数量级的。通过缓存技术无论是在读还是写方面都可以大大提 高数据库整体性能。Innodb_buffer_pool_size 的合理设置Innodb…

用过美德乐吸奶器的宝妈们感觉比国产吸奶器怎么样啊?

药效好不好&#xff0c;看疗效就知道。吸奶器好不好看评价就知道。我们来看看美德乐吸奶器 天猫旗舰店 : http://medela.wang 的宝妈们的评价如可 拔奶神器&#xff0c;绝对好过贝亲&#xff01;最初一次七八十&#xff0c;后来一百多&#xff0c;现在可以翻个倍。结合宝宝吮吸…

小程序地图多个 circles 使用demo

效果图&#xff1a; 代码&#xff1a; var that; const app getApp() const util require("../../utils/util.js") const data require("../../utils/map.js") Page({data: {pageShow: false,scale: 15,obj: {},longitude: 116.34665554470486,latitud…

编写文档_如何通过编写优质文档来使自己的未来快乐

编写文档by Gabriele Cimato加布里埃莱西马托(Gabriele Cimato) 如何通过编写优质文档来使自己的未来快乐 (How to make your future self happy by writing good docs) 或者&#xff0c;在清除旧代码库时如何减少痛苦 (Or how to be less miserable when dusting off an old …

(转载)人人都会OSGI--实例讲解OSGI开发

http://longdick.iteye.com/blog/457310转载于:https://www.cnblogs.com/eecs2016/articles/7422310.html

小程序json字符串转 json对象 { name :你好} 转成 { name :你好}

解决后端接口返回 var obj "{ name :"你好"}" 类似这样的数据&#xff0c;对象或者数组外面包了一层引号&#xff0c; 把这种数据转成 var obj { name :"你好"}&#xff1b; 直接上代码&#xff1a; // pages/test/test.js Page({jsonStrToJ…

每天写的叫工作日志,每周写的总结叫周报,每月写的叫月报

有些时候&#xff0c;老板会突发让您求每天都要写工作周报&#xff0c;什么项目什么任务&#xff0c;完成情况&#xff0c;完成花费的时间等&#xff0c;然后汇总部门周报&#xff1b;也不是写不出&#xff0c;只是不知道有时候重复做一个项目&#xff0c;到底每天有什么好写&a…