枚举
枚举是在JDK1.5以后引入的。
主要用途:将一组常量组织起来。
这里创建一个名为TestEnum的枚举类型:
public enum TestEnum {
RED,BLACK,GREEN;
}
优点:将常量组织起来统一进行管理(枚举类型都是常量,一般都用大写字母表示)
应用场景:错误状态码,消息类型,颜色的划分,状态机等
本质:是java.lang.Enum 的子类,也就是说TestEnum默认继承了java.lang.Enum这个类。
1 enum枚举在switch语句中使用
public class Main {
public enum TestEnum{
RED,BLACK,GREEN;
}
public static void main(String[] args) {
TestEnum testEnum2 = TestEnum.BLACK;
System.out.println(testEnum2);
switch (testEnum2) {
case RED:
System.out.println("red");
break;
case BLACK:
System.out.println("black");
break;
default:
break;
}
}
}
结果:
BLACK
black
2 Enum 类的常用方法
-
values()
以数组形式返回枚举类型的所有成员(保持在enum中的声明顺序) -
ordinal()
获取枚举成员的索引位置(索引位置从0开始) -
valueOf()
将给定的字符串转换为枚举实例,如果不存在将会抛出异常。(TestEnum.valueOf(“GREEN”)) -
compareTo()
比较两个枚举成员在定义时的顺序,Enum类实现了Comparable接口,所以它具有compareTo()方法。
public class Main {
public enum TestEnum{
RED,BLACK,GREEN;
}
public static void main(String[] args) {
for(TestEnum x:TestEnum.values()){
System.out.println(x+"的索引位置为:"+x.ordinal());
System.out.println(x.compareTo(TestEnum.RED));
System.out.println(x.getDeclaringClass());
System.out.println(x.name());
}
System.out.println(TestEnum.valueOf("RED"));
}
}
部分结果:
RED的索引位置为:0
0
class com.Main$TestEnum
RED
BLACK的索引位置为:1
1
class com.Main$TestEnum
BLACK
.
.
.
RED
- 调用getDeclaringClass()方法就能知道enum实例所属的类
- name()返回enum声明时的名字。
- enum中重写了toString()方法,所以可以直接打印枚举实例的名字。
3 枚举——常规类
我们可以将enum看作一个常规的类,除了不能继承它。我们可以向enum中添加方法,enum中也可以有main方法。
注意:
enum中枚举实例的声明必须放在最前面,否则会报错。
在Java当中枚举实际上就是一个类。
public enum TestEnum {
RED("red",1),BLACK("black",2),WHITE("white",3);
private String name;
private int key;
private TestEnum (String name,int key) {
this.name = name;
this.key = key;
}
public static TestEnum getEnumKey (int key) {
for (TestEnum t: TestEnum.values()) {
if(t.key == key) {
return t;
}
}
return null;
}
public static void main(String[] args) {
System.out.println(getEnumKey(2));
}
}
在枚举中构造方法限制为私有
,在我们访问枚举实例时会执行构造方法,同时每个枚举实例都是static final
类型的,也就表明只能被实例化一次。在调用构造方法时,enum中的实例被保证只会被实例化一次.因此我们可以利用枚举实现单例模式。普通类的私有构造方法可以通过反射拿到,而枚举类的私有构造方法并不能用反射拿到,所以使用枚举实现单例也是比较安全的。
4 下面简单介绍一下为什么反射不能用于枚举类
java.lang.Enum这个类中的构造方法:
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
当我们想通过反射拿到枚举类的构造方法时,报错了。
public static void main(String[] args) {
try {
Class<?> c1 = Class.forName("TestEnum");
Constructor constructor = c1.getDeclaredConstructor(String.class,int.class,String.class,int.class);
System.out.println(constructor);
constructor.setAccessible(true);
TestEnum testEnum =(TestEnum) constructor.newInstance("red",1,"black",2);
System.out.println(testEnum);
} catch (Exception e) {
e.printStackTrace();
}
}
结果:
java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:482)
at reflectdemo.main(reflectdemo.java:12)
我们进入反射源码中发现我们在用newInstance获取枚举类的实例时,有一个if语句,如果是枚举类将会直接抛出异常,也就是说枚举类是不能通过反射获取内部的构造方法的:
public T newInstance(Object ... initargs){
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
注意:TestEnum testEnum =(TestEnum) constructor.newInstance("red",1,"black",2);
这里因为父类中也有有参构造方法,所以我们也需要帮助父类构造方法。