1. 枚举的概念
Java中的枚举是一种特殊的数据类型,它允许程序员定义一个固定的一组常量,这些常量可以作为变量在程序中使用。
在Java中,枚举被定义为一个特殊的类,其中每个枚举常量都是该类的一个实例。
2. 枚举的使用
定义一个枚举需要使用enum关键字,枚举中的常量都用大写字母命名,每个常量用逗号分隔。例如:
public enum TestEnum {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}
枚举可以结合switch使用
public class Main {
public static void main(String[] args) {
//注意,enum 类型是不能 new 的
TestEnum testEnum = TestEnum.MONDAY;
switch(testEnum){
case MONDAY:
System.out.println("MONDAY");
break;
case TUESDAY:
System.out.println("TUESDAY");
break;
case WEDNESDAY:
System.out.println("WEDNESDAY");
break;
case THURSDAY:
System.out.println("THURSDAY");
break;
case FRIDAY:
System.out.println("FRIDAY");
break;
case SATURDAY:
System.out.println("SATURDAY");
break;
case SUNDAY:
System.out.println("SUNDAY");
break;
default:
System.out.println("非法输入");
break;
}
}
}
结果:
MONDAY
在定义枚举的时候,它会默认继承java.lang.Enum这个类,它提供的常用方法:
| 返回类型 | 方法名 | 描述 |
|---|---|---|
| String | name() | 返回枚举常量的名称。 |
| int | ordinal() | 返回枚举常量在枚举类中的位置,位置从0开始计数。 |
| int | compareTo(Enum e) | 按照枚举常量在枚举类中的位置进行比较。 |
| T | valueOf(Class enumType, String name) | 根据枚举常量的名称返回对应的枚举常量。 |
| T[] | values() | 返回枚举类中所有的枚举常量 |
| T | valueOf(String name) | 返回一个指定名称的枚举常量 |
案例:
public static void main(String[] args) {
//获取所有的枚举常量
TestEnum[] testEnum = TestEnum.values();
//遍历所有的枚举常量,并打印下标
for (int i = 0; i < testEnum.length; i++) {
System.out.println(testEnum[i] + ": " + testEnum[i].ordinal());
}
}
结果:
MONDAY: 0
TUESDAY: 1
WEDNESDAY: 2
THURSDAY: 3
FRIDAY: 4
SATURDAY: 5
SUNDAY: 6
你会发现在Enum类中没有values()这个方法:
这是为什么呢?values()是由编译器自动添加到每个枚举类型中的。这个方法返回的是一个包含枚举类中所有枚举常量的数组,数组的顺序按照常量在定义时的顺序排列。
2.1 枚举的构造方法
在枚举中可以定义属性、方法等,就像普通的类那样,其中最重要的是,枚举的构造方法默认是私有的。
普通类的构造方法调用时机是 new 的时候;而枚举比较特殊,枚举类的构造方法在枚举常量被创建时调用,而且只会被调用一次。枚举常量的创建是在枚举类被加载时自动进行的,因此可以保证枚举常量的唯一性。
假设我们要定义一个枚举类型来表示颜色,其中每个枚举常量都有三个属性:红色、绿色和蓝色分量。可以这样定义:
public enum Color {
RED(255, 0, 0),
GREEN(0, 255, 0),
BLUE(0, 0, 255);
private final int red;
private final int green;
private final int blue;
private Color(int red, int green, int blue) {
this.red = red;
this.green = green;
this.blue = blue;
}
public int getRed() {
return red;
}
public int getGreen() {
return green;
}
public int getBlue() {
return blue;
}
}
在这个例子中,每个枚举常量都有三个属性:red、green和blue,表示红色、绿色和蓝色分量。在枚举常量被创建时,括号中的参数会被传入构造方法,用于初始化枚举常量的属性。例如,RED枚举常量的构造方法被调用时,会将255, 0, 0作为参数传入,用于初始化red、green和blue属性。
public static void main(String[] args) {
Color color = Color.BLUE;
System.out.println(color.getRed());
System.out.println(color.getGreen());
System.out.println(color.getBlue());
}
结果:
0
0
255
3. 枚举与反射
我们尝试反射枚举类型:
public class ReflectEnum {
public enum Color {
RED, GREEN, BLUE;
private Color() {
System.out.println("调用了私有构造方法");
}
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Constructor<?> constructor = Color.class.getDeclaredConstructor();
constructor.setAccessible(true);
Color red = (Color) constructor.newInstance();
}
}
运行结果:
报错的信息表示没有这个构造方法,但是里面是有一个这样的构造方法的,为什么还报错了呢?
还记得枚举类型默认继承的是java.lang.Enum这个类,而这个父类里面也有一个构造方法,并且只有这一个:
也就是说先初始化父类构造方法再初始化子类构造方法,要注意的是枚举的子类构造方法默认掉用父类构造方法,所以改一下代码:
public class ReflectEnum {
public enum Color {
RED, GREEN, BLUE;
private Color() {
System.out.println("调用了私有构造方法");
}
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//改动
Constructor<?> constructor =
Color.class.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
Color red = (Color) constructor.newInstance("RED",10);
}
}
结果:
现在报了这个错误,没错,就是不能反射地创建枚举对象!!!
我们点进newInstance() 方法的源码,发现如下: