枚举主要用途是:将一组常量组织起来,在这之前表示一组常量通常使用定义常量的方式:
比如下面的例子:
- 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;
- }
创建枚举类
- 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;
- }
- }
- }
方法名称 | 描述 |
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的源码,注意到这句话
这句话意思是当我们试图创建一个枚举类时,程序就会抛一个异常出来,不允许我们创建这个类
所以不可以用反射来实例化一个枚举对象
换句话说,枚举十分安全。特别地,用枚举来实现单例模式非常安全