数据结构:枚举
概念
枚举主要用途是:将一组常量组织起来,在这之前表示一组常量通常使用定义常量的方式:
比如下面的例子:
public static final int RED = 1;
public static final int GREEN = 2;
public static final int BLACK = 3;
利用常量表示RED,GREEN,BLACK既繁琐又容易出错
如果程序里面还有一个int a = 1,那程序可能会认为是RED,用枚举来组织可以轻松解决这些问题
public enum TestEnum {
RED,BLACK,GREEN;
}
创建枚举类
使用
1.用switch语句来匹配对应的颜色
public enum TestEnum {
RED,GREEN,BLACK;
public static void main(String[] args) {
TestEnum color = RED;//定义目标颜色
switch(color){
case GREEN:
System.out.println("GREEN");
break;
case RED:
System.out.println("RED");
break;
case BLACK:
System.out.println("BLACK");
break;
default:
System.out.println("error");
break;
}
}
}
2.常用方法
方法名称 | 描述 |
values() | 以数组的形式返回枚举成员 |
ordinal() | 获取枚举成员索引位置 |
valueOf() | 将普通字符串转成枚举实例 |
compareTo() | 比较两个枚举成员在定义时的顺序 |
这些方法是被继承过来的,默认继承于枚举类
但是我们在这里面没有找到values,那这个方法怎么可以被调用呢?
这是由于java编译器在对enum关键字进行处理时,实际上是将enum转换成为了java.lang.Enum类的一个子类来完成,而这个子类中含有values()静态方法。这一点,可以通过反编译enum类来查看。
如图,通过javap反编译enum枚举类,可以看到编译器在对enum处理时,实际上是转换成了Enum的一个子类来实现的,里面可以看到有values()静态方法的声明。
枚举的构造方法
⚠枚举构造方法默认是private的,所以写不写private没影响
RED(1,"红色"),
GREEN(2,"绿色"),
BLACK(3,"黑色");
private int ordinal;
private String color;
TestEnum(int ordinal, String color){
this.ordinal = ordinal;
this.color = color;
}
这也是枚举本身的一个缺点,它无法继承也无法扩展
枚举和反射
既然枚举里面的构造方法是私有的,那我们可不可以用反射来实例化一个枚举对象呢?
我们来试试看
public static void func() throws ClassNotFoundException, NoSuchMethodException,
InvocationTargetException, InstantiationException,
IllegalAccessException {
//反射Enum类
Class<?> c1 = Class.forName("demo2.TestEnum");
//获取Enum类里面私有变量的类型
Constructor<?> constructor = c1.getDeclaredConstructor(int.class, String.class);
constructor.setAccessible(true);//私有的要设置true,允许获取
//实例化新对象
TestEnum testEnum = (TestEnum) constructor.newInstance(6,"棕色");
System.out.println(testEnum);
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException,
InvocationTargetException, InstantiationException,
IllegalAccessException {
func();
}
当我们运行起来的时候,发现程序报错了
报错信息说我没有int, java.lang.String这两个参数
诶我在前面的构造方法不是传入这两个参数了吗?
其实我一开始写的TestEnum是继承于Enum这个类的,相当于我们既要反射TestEnum类,也要反射Enum类
(Enum里面的构造函数)
也就是说我们在c1.getDeclaredConstructor()里面传入四个参数,🆗我照做
但是怎么又抛了一个异常给我
我们点开Constructor的源码,注意到这句话
这句话意思是当我们试图创建一个枚举类时,程序就会抛一个异常出来,不允许我们创建这个类
所以不可以用反射来实例化一个枚举对象
换句话说,枚举十分安全。特别地,用枚举来实现单例模式非常安全