Java中的EnumMap类
EnumMap是枚举类型的Map接口的专门实现。它扩展了AbstractMap并在Java中实现了Map接口。它属于java.util包。EnumMap的一些重要特点如下:
- EnumMap类是Java集合框架的成员,并且不同步。
- EnumMap是一个有序的集合,它们以它们的键的自然顺序维护(键的自然顺序是指在枚举类型中声明枚举常量的顺序)
- 它是一个高性能的Map实现,比HashMap要快得多。
- 每个EnumMap实例的所有键都必须是单个枚举类型的键。
- EnumMap不允许空键,当我们尝试插入空键时,它会抛出NullPointerException。
- 集合视图返回的迭代器是弱一致性的:它们永远不会抛出ConcurrentModificationException,它们可能或可能不会显示在迭代正在进行时发生的任何对Map的修改的影响。
- EnumMap在内部表示为数组。 这种表示非常紧凑和高效。
语法: 声明
public class EnumMap<K extends Enum<K>,V> extends AbstractMap<K,V> implements Serializable, Cloneable
参数:
- 键对象类型
- 值对象类型
K 必须扩展Enum,这使得键必须是指定的枚举类型的要求得到执行。
Java中的EnumMap类是专门为枚举键而设计的一种专用的Map实现。 EnumMap是使用HashMap与枚举键的紧凑,高效,快速的替代品。
下面是如何在Java中使用EnumMap类的示例:
import java.util.EnumMap;
enum Days {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public class EnumMapExample {
public static void main(String[] args) {
EnumMap<Days, String> schedule = new EnumMap<>(Days.class);
// 将元素添加到EnumMap
schedule.put(Days.MONDAY, "Work");
schedule.put(Days.TUESDAY, "Work");
schedule.put(Days.WEDNESDAY, "Study");
schedule.put(Days.THURSDAY, "Study");
schedule.put(Days.FRIDAY, "Relax");
// 从EnumMap获取元素
System.out.println(schedule.get(Days.MONDAY)); // 输出:Work
System.out.println(schedule.get(Days.FRIDAY)); // 输出:Relax
}
}
输出:
Work
Relax
在这个例子中,我们定义了一个代表星期几的枚举类型Days。然后我们创建一个EnumMap并使用put方法向其中添加元素。最后,我们使用get方法从EnumMap检索元素并将结果打印到控制台。
使用EnumMap的优点:
- 高效:EnumMap类快速高效地访问存储在Map中的元素,使其成为性能关键型应用程序的良好选择。
- 紧凑:EnumMap类使用紧凑的表示形式表示Map,这意味着它需要的内存比HashMap或TreeMap要少。
- 类型安全:EnumMap类只允许指定枚举类型的键,这意味着它提供类型安全行为并消除了需要进行类型转换的需要。
- 排序键:EnumMap类提供排序键,这意味着Map中的元素按照枚举常量声明的顺序排列。
使用EnumMap的缺点:
- 仅限于使用枚举作为键:EnumMap类仅能用于枚举类型的键,这意味着它不适用于其他类型的键。
- 键不可变:EnumMap类使用枚举键,它们是不可变的,一旦创建便不能修改。
EnumMap层次结构

EnumMap构造函数
- EnumMap(Class keyType): 构造函数用于创建一个指定键类型的空EnumMap。
- EnumMap(EnumMap m): 构造函数用于创建一个枚举映射表,其键类型与指定枚举映射表相同,初始映射也与EnumMap相同。
- EnumMap(Map m): 构造函数用于从指定参数中的映射初始化枚举映射表。
示例
// Java Program to illustrate Working of EnumMap class
// and its functions
// Importing EnumMap class
import java.util.EnumMap;
// Main class
public class EnumMapExample {
// Enum
public enum GFG {
CODE,
CONTRIBUTE,
QUIZ,
MCQ;
}
// Main driver method
public static void main(String args[])
{
// Java EnumMap
// Creating an empty EnumMap with key
// as enum type state
EnumMap<GFG, String> gfgMap
= new EnumMap<GFG, String>(GFG.class);
// Putting values inside EnumMap in Java
// Inserting Enum keys different from
// their natural order
gfgMap.put(GFG.CODE, "Start Coding with gfg");
gfgMap.put(GFG.CONTRIBUTE, "Contribute for others");
gfgMap.put(GFG.QUIZ, "Practice Quizes");
gfgMap.put(GFG.MCQ, "Test Speed with Mcqs");
// Printing size of EnumMap
System.out.println("Size of EnumMap in java: "
+ gfgMap.size());
// Printing Java EnumMap
// Print EnumMap in natural order
// of enum keys (order on which they are declared)
System.out.println("EnumMap: " + gfgMap);
// Retrieving value from EnumMap
System.out.println("Key : " + GFG.CODE + " Value: "
+ gfgMap.get(GFG.CODE));
// Checking if EnumMap contains a particular key
System.out.println(
"Does gfgMap has " + GFG.CONTRIBUTE + ": "
+ gfgMap.containsKey(GFG.CONTRIBUTE));
// Checking if EnumMap contains a particular value
System.out.println(
"Does gfgMap has :" + GFG.QUIZ + " : "
+ gfgMap.containsValue("Practice Quizes"));
System.out.println("Does gfgMap has :" + GFG.QUIZ
+ " : "
+ gfgMap.containsValue(null));
}
}
输出
Size of EnumMap in java: 4
EnumMap: {CODE=Start Coding with gfg, CONTRIBUTE=Contribute for others, QUIZ=Practice Quizes, MCQ=Test Speed with Mcqs}
Key : CODE Value: Start Coding with gfg
Does gfgMap has CONTRIBUTE: true
Does gfgMap has :QUIZ : true
Does gfgMap has :QUIZ : false
EnumMap的基本操作
操作1: 添加元素
为了向EnumMap中添加元素,我们可以使用put()或putAll()方法,如下所示。
// Java Program to Remove Elements from EnumMap
// Importing required classes
import java.util.EnumMap;
// Main class
// RemoveElementsFromEnumMap
class GFG {
// Enum
enum Color { RED, GREEN, BLUE, WHITE }
// Main driver method
public static void main(String[] arg)
{
// Creating an EnumMap of the Color enum
EnumMap<Color, Integer> colors
= new EnumMap<>(Color.class);
// Inserting elements using put() method
colors.put(Color.RED, 1);
colors.put(Color.GREEN, 2);
colors.put(Color.BLUE, 3);
colors.put(Color.WHITE, 4);
// Printing elements of the map
System.out.println("EnumMap before removal : " + colors);
// Removing elements using remove() method
colors.remove(Color.BLUE);
System.out.println("EnumMap after removal of BLUE : " + colors);
// Removing elements using removeAll() method
colors.removeAll(colors);
System.out.println("EnumMap after invoking removeAll() : " + colors);
}
}
输出
EnumMap before removal : {RED=1, GREEN=2, BLUE=3, WHITE=4}
EnumMap after removal of BLUE : {RED=1, GREEN=2, WHITE=4}
EnumMap after invoking removeAll() : {}
// Java程序:删除EnumMap元素
// 导入EnumMap类
import java.util.EnumMap;
// 主类
class GFG {
// 枚举
enum Color {
// 自定义元素
RED,
GREEN,
BLUE,
WHITE
}
// 主方法
public static void main(String[] args)
{
// 创建颜色枚举的EnumMap
EnumMap<Color, Integer> colors
= new EnumMap<>(Color.class);
// 使用put()方法在Map中插入元素
colors.put(Color.RED, 1);
colors.put(Color.GREEN, 2);
colors.put(Color.BLUE, 3);
colors.put(Color.WHITE, 4);
// 在控制台输出EnumMap中的颜色
System.out.println("EnumMap colors : " + colors);
// 使用remove()方法去除一个mapping
int value = colors.remove(Color.WHITE);
// 显示删除的值
System.out.println("Removed Value: " + value);
// 删除特定颜色并存储布尔值,显示是否删除
boolean result = colors.remove(Color.RED, 1);
// 将该布尔值打印到控制台
System.out.println("Is the entry {RED=1} removed? "
+ result);
// 打印更新后的Map到控制台
System.out.println("Updated EnumMap: " + colors);
}
}
输出
EnumMap colors : {RED=1, GREEN=2, BLUE=3, WHITE=4}
Removed Value: 4
Is the entry {RED=1} removed? true
Updated EnumMap: {GREEN=2, BLUE=3}
操作4: 替换元素
Map接口提供了三种替换EnumMap映射的方式。
示例
// Java程序:替换EnumMap元素
// 导入所需类
import java.util.EnumMap;
// 主类
class GFG {
// 枚举
enum Color {
RED,
GREEN,
BLUE,
WHITE
}
// 主方法
public static void main(String[] args)
{
// 创建颜色枚举的EnumMap
EnumMap<Color, Integer> colors
= new EnumMap<>(Color.class);
// 使用put()方法将元素插入Map中
colors.put(Color.RED, 1);
colors.put(Color.GREEN, 2);
colors.put(Color.BLUE, 3);
colors.put(Color.WHITE, 4);
// 在控制台输出map中的所有元素
System.out.println("EnumMap colors " + colors);
// 替换表示颜色的某些元素
colors.replace(Color.RED, 11);
colors.replace(Color.GREEN, 2, 12);
// 打印更新后的元素
System.out.println("EnumMap using replace(): "
+ colors);
// 使用replaceAll()方法替换所有颜色
colors.replaceAll((key, oldValue) -> oldValue + 3);
// 打印上述Map的所有元素
System.out.println("EnumMap using replaceAll(): "
+ colors);
}
}
输出
EnumMap colors {RED=1, GREEN=2, BLUE=3, WHITE=4}
EnumMap using replace(): {RED=11, GREEN=12, BLUE=3, WHITE=4}
EnumMap using replaceAll(): {RED=14, GREEN=15, BLUE=6, WHITE=7}
同步EnumMap
EnumMap的实现是不同步的。这意味着如果多个线程同时访问一个树集合,而至少有一个线程修改了集合,那么它必须在外部进行同步。通常可以通过使用Collections类的synchronizedMap()方法来实现。最好在创建时完成此操作,以防止意外的非同步访问。
Map<EnumKey, V> m = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...));
EnumMap的方法
- K – 键对象的类型
- V – 值对象的类型
| 方法 | 行为 |
|---|---|
| clear() | 删除此映射中的所有映射。 |
| clone() | 返回此枚举映射的浅表副本。 |
| containsKey(Object key) | 如果此映射包含指定键的映射,则返回true。 |
| containsValue(Object value) | 如果此映射将一个或多个键映射到指定值,则返回true。 |
| entrySet() | 返回此映射中所包含的映射的 Set 视图。 |
| equals(Object o) | 比较指定对象与此映射的相等性。 |
| get(Object key) | 返回指定键所映射的值,如果此映射不包含该键的映射,则返回null。 |
| hashCode() | 返回此映射的哈希码值。 |
| keySet() | 返回此映射中所包含的键的 Set 视图。 |
| put(K key, V value) | 在此映射中将指定值与指定键关联。 |
| putAll(Map<? extends K,? extends V> m) | 将指定映射中的所有映射复制到此映射中。 |
| remove(Object key) | 从此映射中删除指定键的映射(如果存在)。 |
| size() | 返回此映射中键-值映射关系的数量。 |
| values() | 返回此映射中包含的值的 Collection 视图。 |
在AbstractMap类中声明的方法
| 方法 | 描述 |
|---|---|
| isEmpty() | 如果此映射未包含键值映射,则返回true。 |
| toString() | 返回此Map的字符串表示形式。 |
在接口java.util.Map中声明的方法
本文涉及了 EnumMap 类的方法以及 AbstractMap 和 java.util.Map 接口中声明的方法。在使用 EnumMap 时,需要注意其实现是不同步的,并且多线程同时访问时需要进行外部同步。通常可以通过使用 Collections 类中的 synchronizedMap() 方法进行同步。此外,本文中还介绍了 EnumMap 类中的各种方法以及在 AbstractMap 类和 java.util.Map 接口中声明的方法,供读者参考。
| 方法 | 描述 |
|---|---|
| compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction) | 尝试计算指定键及其当前映射值(如果当前没有映射则为null)的映射。 |
| computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction) | 如果指定的键没有关联值(或映射为null),则尝试使用给定的映射函数计算其值并将其输入到该映射中,除非null。 |
| computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction) | 如果指定键的值存在且不为null,则尝试计算给定键及其当前映射值的新映射。 |
| forEach(BiConsumer<? super K,? super V> action) | 对该映射中的每个条目执行给定的操作,直到所有条目都被处理或操作引发异常。 |
| getOrDefault(Object key, V defaultValue) | 返回指定键映射到的值,如果该映射不包含该键的映射,则返回defaultValue。 |
| merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction) | 如果指定键尚未与值关联或者已关联null,则将其关联为给定的非null值。 |
| putIfAbsent(K key, V value) | 如果指定键尚未关联值(或映射为null),则将其关联为给定的值并返回null,否则返回当前值。 |
| remove(Object key, Object value) | 仅当指定键当前映射到指定值时,才删除该键的条目。 |
| replace(K key, V value) | 仅当指定键当前映射到某个值时,才替换该键的条目。 |
| replace(K key, V oldValue, V newValue) | 仅当指定键当前映射到指定值时,才替换该键的条目。 |
| replaceAll(BiFunction<? super K,? super V,? extends V> function) | 使用对每个条目调用该函数的结果替换每个条目的值,直到所有条目都被处理或函数抛出异常。 |
EnumMap vs EnumSet
| 属性 | EnumMap | EnumSet |
|---|---|---|
| 内部表示 | EnumMap是以数组的形式进行内部表示的。该表示方法紧凑高效。 | EnumSet是以位向量或位序列作为内部表示的。 |
| 允许空元素吗? | 不允许使用空键,但允许使用空值。 | 不允许使用空元素。 |
| 是否为抽象类? | 否 | 是 |
| 实例化 | 由于EnumMap不是抽象类,可以使用new运算符进行实例化。 | 它是一个抽象类,没有构造函数。使用其预定义的方法(如allOf()、noneOf()、of()等)创建枚举集。 |
| 实现 | EnumMap是专为枚举类型键设计的特殊Map实现。 | EnumSet是专为枚举类型设计的特殊Set实现。 |
示例:
解释
EnumMap是Java中Map接口的专门指定实现,旨在与枚举作为键一起使用。它是一种高性能的实现,可以保证在许多基本操作(如get()和put())中具有常数时间性能。
EnumMap类是一个强类型的Map实现,这意味着它只能与枚举作为键一起使用。EnumMap的每个实例都与特定的枚举类相关联,map的键集是枚举值的一个子集。这确保了键始终是独特且定义明确的。
使用EnumMap的主要优势之一是其性能。由于它是专门为枚举使用而设计的,因此可以优化以利用枚举的独特属性。例如,EnumMap实现使用紧凑的基于数组的数据结构,为许多基本操作提供了常数时间性能。
极客教程