Java枚举
# Java枚举
# 什么是枚举
枚举就是把对象或者属性值一个一个地列举出来。而枚举类就是起到把类属性值一个一个列举出来的作用,枚举类是java5中提出的新概念。
枚举类在 Java 中实际上是一个特殊的类。虽然
enum
关键字用于定义枚举类型,但枚举类本质上是一个继承自java.lang.Enum
的类。
# 枚举类的诞生
在没有枚举类之前,开发者通常使用常量来表示一组固定的值,(至于为何使用static、final则为了属性值方便使用、和属性值不变)例如:
public class Color {
public static final int RED = 1;
public static final int GREEN = 2;
public static final int BLUE = 3;
}
2
3
4
5
这种方法存在几个问题:
- 类型不安全:这些常量的类型是
int
,容易与其他int
类型的变量混淆。 - 容易出错:如果传入了一个不在预期范围内的
int
值,编译器无法检测到错误。
使用枚举类可以确保类型安全:
public enum Color {
RED, GREEN, BLUE
}
2
3
现在,Color
是一个独立的类型,编译器会检查传递的值是否属于 Color
枚举类型。
以下是一个关于类型不安全的例子:
public class Color {
public static final int RED = 1;
public static final int GREEN = 2;
public static final int BLUE = 3;
}
public class Main {
public static void main(String[] args) {
int color = 4; // 传入了一个非法值
processColor(color);
}
public static void processColor(int color) {
switch (color) {
case Color.RED:
System.out.println("Red");
break;
case Color.GREEN:
System.out.println("Green");
break;
case Color.BLUE:
System.out.println("Blue");
break;
default:
System.out.println("Unknown color"); // 处理非法值
break;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
在这个例子中,color
变量被赋值为 4
,这是一个非法值。编译器无法检测到这个错误,运行时会输出 "Unknown color"。
而使用枚举类则可以确保类型安全
,因为枚举常量是类型安全的,编译器会检查传递的值是否属于枚举类型。
# 枚举类的优势
此外,枚举类还有以下几个优势:
- 确保类型安全
- 语义更清晰
- 防止重复
- 提供了更多功能
枚举类提供了更好的语义,使得代码更具可读性和可维护性。例如:
public void setTrafficLight(Color color) {
// 处理交通灯的颜色
}
setTrafficLight(Color.RED); // 明确表示设置交通灯为红色
2
3
4
5
枚举类确保了常量的唯一性,避免了重复定义。例如,多个常量可能被定义为相同的值,导致混淆:
public class Status {
public static final int ACTIVE = 1;
public static final int INACTIVE = 1; // 错误:重复定义
}
2
3
4
使用枚举类可以避免这种情况:
public enum Status {
ACTIVE, INACTIVE
}
2
3
枚举类不仅仅是常量的集合,还可以包含方法、字段和构造函数,从而提供更多的功能。例如:
public enum Color {
RED("红色"), GREEN("绿色"), BLUE("蓝色");
private String displayName;
Color(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# 枚举类的定义
在 Java 中,定义枚举类使用 enum
关键字。枚举类可以包含常量、方法、字段和构造函数,使其具备更多的功能。
# 简单的定义
最简单的枚举类只包含一组常量:
public enum DayOfWeek {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
// 以下为 使用方法
DayOfWeek today = DayOfWeek.FRIDAY;
// 直接 类名.常量名 即可
2
3
4
5
6
注意:枚举类的常量(MONDAY这些)不是 String
类型,而是枚举类型本身。具体来说,DayOfWeek
枚举类中的 MONDAY
、TUESDAY
等常量的类型是 DayOfWeek
。
# 原理探究
看到使用方法,是否想到了static关键字,没错。它的内部实现确实使用了static。
在 Java 中,枚举类本质上是一个特殊的类,每个枚举常量都是这个类的一个实例。这些实例在编译时创建,并且是唯一的、不可变的。
public enum DayOfWeek {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
2
3
在这个例子中,MONDAY
、TUESDAY
、WEDNESDAY
、THURSDAY
、FRIDAY
、SATURDAY
和 SUNDAY
都是 DayOfWeek
类的实例。这些实例在编译时创建,并且在整个应用程序的生命周期中是唯一的。
# 枚举类的内部结构
为了更好地理解这一点,可以看看枚举类的内部结构。编译器会将枚举类编译成类似于以下的类:
public final class DayOfWeek extends Enum<DayOfWeek> {
public static final DayOfWeek MONDAY = new DayOfWeek("MONDAY", 0);
public static final DayOfWeek TUESDAY = new DayOfWeek("TUESDAY", 1);
public static final DayOfWeek WEDNESDAY = new DayOfWeek("WEDNESDAY", 2);
public static final DayOfWeek THURSDAY = new DayOfWeek("THURSDAY", 3);
public static final DayOfWeek FRIDAY = new DayOfWeek("FRIDAY", 4);
public static final DayOfWeek SATURDAY = new DayOfWeek("SATURDAY", 5);
public static final DayOfWeek SUNDAY = new DayOfWeek("SUNDAY", 6);
private DayOfWeek(String name, int ordinal) {
super(name, ordinal);
}
public static DayOfWeek[] values() {
return (DayOfWeek[]) $VALUES.clone();
}
public static DayOfWeek valueOf(String name) {
return (DayOfWeek) Enum.valueOf(DayOfWeek.class, name);
}
private static final DayOfWeek[] $VALUES = new DayOfWeek[] {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
};
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- 构造函数:每个枚举常量都是通过调用枚举类的私有构造函数创建的。构造函数接受两个参数:
name
和ordinal
,分别表示枚举常量的名称和序号。 - 唯一性:每个枚举常量在编译时创建,并且是唯一的。这些实例在运行时不会被重新创建。
- 不可变性:枚举常量是不可变的,一旦创建,它们的值不能被修改。
- 类型安全:枚举常量的类型是枚举类本身,确保了类型安全。
好了下面让我们继续介绍它的定义方式。
# 带有构造函数和字段的枚举
枚举类可以包含构造函数和字段,用于存储额外的信息:
public enum Color {
RED("红色"),
GREEN("绿色"),
BLUE("蓝色");
private String displayName;
// 构造函数
Color(String displayName) {
this.displayName = displayName;
}
// 获取显示名称的方法
public String getDisplayName() {
return displayName;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 带有方法的枚举
枚举类可以包含方法,提供更多的功能:
public enum Planet {
MERCURY(3.303e+23, 2.4397e6),
VENUS(4.869e+24, 6.0518e6),
EARTH(5.976e+24, 6.37814e6),
MARS(6.421e+23, 3.3972e6),
JUPITER(1.9e+27, 7.1492e7),
SATURN(5.688e+26, 6.0268e7),
URANUS(8.686e+25, 2.5559e7),
NEPTUNE(1.024e+26, 2.4746e7);
private final double mass; // in kilograms
private final double radius; // in meters
// 构造函数
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
// 获取质量的方法
public double getMass() {
return mass;
}
// 获取半径的方法
public double getRadius() {
return radius;
}
// 计算重力加速度的方法
public double surfaceGravity() {
if (radius == 0) {
throw new IllegalStateException("Radius cannot be zero");
}
return G * mass / (radius * radius);
}
// 计算表面重量的方法
public double surfaceWeight(double otherMass) {
return otherMass * surfaceGravity();
}
// 引力常数
private static final double G = 6.67300E-11;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45