Java 中很好用的数据结构EnumSet
作者:??苏州程序大白???? 发布时间:2023-12-06 09:37:23
前言
Java 中常规的集合工具,相比大家都熟练于胸,但是如果说有一个集合类你不一定知道或者说肯定没用过,你相不相信呢?今天跟大家介绍的就是 java.util.EnumMap
,也是 java.util
包下面的一个集合类,同样的也有对应的的 java.util.EnumSet,
下面我们看一下吧。
Map
和 Set
结构在我们日常工作的使用的特别多,经常会用来存放数据或者参数传递,不过有些场景在使用 Map 的时候,不知道大家会不会感受到一丝丝的不安,毕竟 Map
的数据设置我们没办法控制,完全不知道别人会 put 一些什么样的数据进去,或者说如果某些场景我们 Map
的数据 Key
的类型和个数是固定,那在这种情况的下,我们如何提升系统的安全性和性能呢?
这个时候我们就可以考虑使用 EnumMap
,EnumMap
顾名思义首先是一个 Map
,其次它的 key
只能是枚举,大家都知道枚举中的实例个数是固定的,而且还是预编译的,所以在很大程度上保证了数据的安全性,同时也可以提升一定的性能。
EnumMap
下面我们来看下如何使用 EnumMap
,首先我们需要创建一个枚举 Color
。
package com.ziyou.demo.enums;
/**
* <br>
* <b>Function:</b><br>
* <b>Author:</b><br>
* <b>Date:</b>2022-04-17 <br>
* <b>Desc:</b>无<br>
*/
public enum Color
{
BLUE("blue", "蓝色"),
RED("red", "红色"),
;
public String color;
public String desc;
Color(String color, String desc)
{
this.color = color;
this.desc = desc;
}
}
在创建一个测试类:
package com.ziyou.demo.enums;
import java.util.EnumMap;
/**
* <br>
* <b>Function:</b><br>
* <b>Author:</b><br>
* <b>Date:</b>2022-04-17 <br>
* <b>Desc:</b>无<br>
*/
public class ColorTest
{
public static void main(String[] args)
{
EnumMap<Color, String> enumMap = new EnumMap<>(Color.class);
enumMap.put(Color.RED, "我是一个红色枚举");
enumMap.put(Color.BLUE, "我是一个蓝色枚举");
System.out.println(enumMap.get(Color.BLUE));
}
}
我们可以看到构造 EnumMap
的时候需要传入一个枚举类,后续的 put
和 get
都跟普通的 Map
一样,只不过这个时候 put
的时候 key
必须是该枚举实例了。接下来我们看下EnumMap
的 put
和 get
方法是如何实现的,查看 JDK
源码我们可以看到。
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);
}
在进行 put
的时候,会先进行类型检查,如果说传进来的不是枚举或者说不是在构造的时候指定的枚举,这里就会抛出异常。当类型检查通过以后,会通过枚举的 ordinal()
方法获取该枚举实例的索引,这个方法会返回一个 int
值,返回的值跟枚举在编写的时候的顺序有关系,比如说我们上面创建的 Color
枚举,Color.BLUE.ordinal()
会返回 0
,Color.RED.ordinal()
会返回 1
。拿到索引过后,就会在对应的数组位置上放上 value
值。
获取数据的时候就更简单了,直接通过 key 获取到索引,然后从数组中那去数据即可。
public V get(Object key)
{
return (isValidKey(key) ?
unmaskNull(vals[((Enum<?>)key).ordinal()]) : null);
}
可以看到整个 EnumMap
的 put
和 get
的效率是非常高的,都是在一维数组中直接根据索引定向处理。所以后续大家在类似的场景中可以尝试使用这种方式来提升性能。
EnumSet
说完了 EnumMap
我们再来看看 EnumSet
,EnumSe
t 是一个用来操作 Enum
的集合,是一个抽象类,它有两个继承类,JumboEnumSet
和 RegularEnumSet
。在使用的时候,需要确定枚举类型。通过下面的方式可以创建一个空的 EnumSet
,在后续进行使用。
public static void main(String[] args)
{
EnumSet<Color> enumSet = EnumSet.noneOf(Color.class);
enumSet.add(Color.BLUE);
enumSet.add(Color.RED);
System.out.println(enumSet.size());
}
EnumSet
的构造方式相对会多一点,我们可以创建空的集合,同时我们也可以直接根据创建一个完整的集合,没必要创建空的然后再进行 add
操作,如下所示:
public static void main(String[] args)
{
EnumSet<Color> enumSet = EnumSet.allOf(Color.class);
System.out.println(enumSet.size());
}
另外前面提到会使用到枚举的 ordinal()
方式,所以我们在构造 EnumSet
的时候还可以只构造指定两个枚举范围之间的所有枚举值,这里要注意 range
方法的第二哥参数的枚举不能在第一个枚举前面。
EnumSet.range(Color.BLUE,Color.RED);
还可以通过 EnumSet
的 of
方法来构造指定的枚举集合,通过源码我们可以发现不管是通过什么方法了构造,底层都是先构造一个空集合,然后将对应的枚举元素添加进行。构造空集合的实现逻辑如下,这里我们可以看到,当枚举个数大于 64
的时候,采用的是 JumboEnumSet
这个子类,否则都是 RegularEnumSet
这个子类,正常来说一个枚举的实例个数超过 64
的会比较少吧。
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType)
{
Enum<?>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
来源:https://juejin.cn/post/7088106378639704094


猜你喜欢
- 说点对这几个容易混淆的词的理解:1、c++中的virtual方法的 virtual关键字主要是防止继承中重复继承父类的同一个方法而设置的标识
- 引言:最近在工作中遇到与某些API对接的post的数据需要将对象的字段首字母小写。解决办法有两种:第一种:使用对象的字段属性设置JsonPr
- 用途项目中使用了 dubbo,注册中心使用的 zookeeper,使用 zookeeper 实现了一个简单的分布式锁(依赖 curator)
- springmvc下载中文文件名称为下划线springboot项目中,在下载文件的时候,通过封装ResponseEntity,将文件流写入b
- 导入项目集成环境:IntelliJ IDEA 2020.1.2演示系统:DELL Windows 10Eclipse项目如何导入IDEA并成
- 本文实例讲述了Hibernate实现批量添加数据的方法。分享给大家供大家参考,具体如下:1.Hibernate_016_Ba
- 最近项目上的一个上传文件功能,项目是MVC+EF+LigerUI 来做的,贴出来大家一起分享下1、页面需要引用这个JS 和 CSS<s
- 类与对象:类是抽象的数据类型,对象是抽象的数据类型的具体化。使用new 关键字创建对象,默认初始化为null一个项目只存在一个main方法,
- Java生成4位、6位随机数短信验证码生成短信验证码问题,本质是产生某个范围内随机数的问题。比如,要生成6位短信验证码xxxxxx:6位数最
- 用来练手还是不错的,分享大家看一下,还是一些新颖点的!哈哈 就是自定义DataGridView,方便每个功能部分调用!简单!再次重
- 本文实例讲述了C#中数组段用法。分享给大家供大家参考。具体分析如下:1.数组段说明① 结构ArraySegment<T>表示数组
- 我们在开发Java项目的时候,经常需要对参数进行一些必填项、格式、长度等进行校验,如果手写代码对参数校验,每个接口会需要很多低级的代码,这样
- 前言尽管可以通过不同的方式组合IO流类,但我们可能也就只用到其中的几种组合。下面的例子可以作为典型的IO用法的基本参考。在这些示例中,异常处
- 前言初识Android PowerManagerService省电模式 让我们省电模式的概念有了初步的认识,Androi
- 这篇文章主要介绍了Java流程控制顺序结构原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可
- 方法一:简单的方法就是改变picturebox 控件的borderstyle样式 currentSelectPicBox.Bord
- 一、背景项目中新建module之后,要在该目录下新增java Class文件,右键——》New发现无Java Class选项。二、办法Fil
- 本文实例讲述了C#编程实现四舍五入、向上及下取整的方法。分享给大家供大家参考,具体如下:在处理一些数据时,我们希望能用“四舍五入”法实现,但
- 前面一篇有说道如何在MyEclipse中搭建maven项目,这里将继续介绍如何在搭建好的基础maven项目中引入我们常用的javaweb框架
- 接口等幂性通俗的来说就是同一时间内,发起多次请求只有一次请求成功;其目的时防止多次提交,数据重复入库,表单验证网络延迟重复提交等问题。比如: