今天咱们来聊一聊一个非常实用的Java技巧——EnumMap
。这玩意儿是我在开发过程中偶然发现的,简直就像是Java中隐藏的一颗宝藏。如果你经常用Map
来做一些基于枚举类型的映射,估计这个工具会让你事半功倍,不信?那就往下看吧!首先,简单介绍一下什么是EnumMap
。很多时候,我们在写代码时会遇到这种需求:需要用Map
来存储枚举值和对应的对象或数据。正常来说,我们可能会用HashMap<EnumType, Object>
来做这个映射。但是,这种方式在性能上并不总是最优,尤其是在枚举类型比较少的时候。那么问题来了,Java到底有没有更高效的方式来处理这种映射呢?答案是有的!那就是EnumMap
。# 什么是EnumMap?
EnumMap
是Java Collections框架中的一个特例化的Map
实现。顾名思义,它是专门用于枚举类型作为键的Map
。它比HashMap
在处理枚举键时要高效得多,原因是什么呢?我们可以通过下面的几个角度来理解:- 内存优化:
EnumMap
内部并不像HashMap
那样使用哈希桶,它直接使用了枚举值的序号。这意味着在内存分配上,EnumMap
会比HashMap
更加高效,因为它不需要额外的空间来存储哈希码。 - 速度提升:由于它是根据枚举值的序号来存储数据,查找操作几乎是常数时间复杂度(O(1)),而不像
HashMap
那样需要计算哈希值,减少了性能开销。 - 类型安全:
EnumMap
要求键必须是枚举类型,这就避免了错误地使用不合适的键类型,增强了类型安全。
# 如何使用EnumMap?
在使用EnumMap
之前,首先你得了解一个条件:它只支持枚举类型的键。你不能在EnumMap
中存储其他类型的对象,像String
或者Integer
这样的类型都不行。基本的创建方式
import java.util.EnumMap;
public class EnumMapExample {
// 定义一个枚举类型
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public static void main(String[] args) {
// 创建一个EnumMap,键为Day枚举类型,值为String
EnumMap<Day, String> enumMap = new EnumMap<>(Day.class);
// 插入一些值
enumMap.put(Day.MONDAY, "Start of the week");
enumMap.put(Day.WEDNESDAY, "Midweek");
enumMap.put(Day.FRIDAY, "Almost weekend");
// 打印
System.out.println(enumMap);
}
}
{MONDAY=Start of the week, WEDNESDAY=Midweek, FRIDAY=Almost weekend}
看,这么简单就创建了一个基于枚举的Map
,而且直接指定了枚举类型作为键。EnumMap
的构造函数接受枚举类型的Class
对象作为参数,所以它是类型安全的。EnumMap的实现原理
EnumMap
的实现非常有意思。它并不像HashMap
那样通过链表和哈希桶来存储数据,而是使用了一个简单的数组来存储对应的值。为什么这么做呢?原因很简单——枚举值本身就是固定的,数量非常有限,因此EnumMap
通过枚举的ordinal()
方法(即枚举值的序号)来直接索引到一个数组的位置,进行存取操作。内部存储
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
EnumMap
会创建一个数组,长度等于枚举值的个数(在这个例子中是7)。数组的每个索引位置会对应枚举中的每一个值。存取元素时,EnumMap
只需要通过Day.MONDAY.ordinal()
来快速定位到数组中的位置。这个方法返回的是MONDAY
在枚举中的位置(0),这样就可以通过数组的索引直接存取数据了。# EnumMap的例子
让我们看一个更复杂的例子,结合一些实际场景来理解EnumMap
的应用。假设你在开发一个简单的周日程管理系统,想要记录每一天的任务。这里,Day
枚举类型就可以作为Map
的键,而每天的任务作为值。import java.util.EnumMap;
public class TaskManager {
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public static void main(String[] args) {
// 创建一个EnumMap,键为Day,值为String
EnumMap<Day, String> taskMap = new EnumMap<>(Day.class);
// 填充任务
taskMap.put(Day.MONDAY, "Meeting with team");
taskMap.put(Day.TUESDAY, "Code review");
taskMap.put(Day.WEDNESDAY, "Research new tech");
taskMap.put(Day.THURSDAY, "Write documentation");
taskMap.put(Day.FRIDAY, "Deploy updates");
taskMap.put(Day.SATURDAY, "Rest");
taskMap.put(Day.SUNDAY, "Plan for next week");
// 打印周日程
taskMap.forEach((day, task) -> System.out.println(day + ": " + task));
}
}
MONDAY: Meeting with team
TUESDAY: Code review
WEDNESDAY: Research new tech
THURSDAY: Write documentation
FRIDAY: Deploy updates
SATURDAY: Rest
SUNDAY: Plan for next week
从上面的例子可以看出,EnumMap
不仅提供了非常高效的存取方式,而且在代码上也非常直观易懂。你只需知道一天的枚举类型,直接取出对应的任务就行了。测试用例
既然说了这么多,怎么确保EnumMap
真的是高效呢?我们来写个简单的性能对比测试,看看它和HashMap
到底差距有多大。import java.util.HashMap;
import java.util.EnumMap;
import java.util.Map;
public class PerformanceTest {
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public static void main(String[] args) {
// 创建HashMap和EnumMap
Map<Day, String> hashMap = new HashMap<>();
Map<Day, String> enumMap = new EnumMap<>(Day.class);
// 插入1000000个数据进行对比
long start = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
hashMap.put(Day.MONDAY, "Task " + i);
}
long end = System.nanoTime();
System.out.println("HashMap插入耗时:" + (end - start) + "ns");
start = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
enumMap.put(Day.MONDAY, "Task " + i);
}
end = System.nanoTime();
System.out.println("EnumMap插入耗时:" + (end - start) + "ns");
}
}
在大量数据插入的情况下,EnumMap
的速度要比HashMap
快得多。尤其在枚举类型的键值较少时,EnumMap
的优势更加明显。总结
好了,今天的内容到这里就差不多了。通过以上的介绍,你应该对EnumMap
有了一个更深的了解。它不仅在性能上比HashMap
更优,而且它的实现方式非常简单明了,适合用在需要频繁查找基于枚举类型映射的场景中。兄弟们你们用上EnumMap
了没?欢迎在评论区分享使用体验!对编程、职场感兴趣的同学,可以链接我,微信:462135539 拉你进入“程序员交流群”。