目录
一、定义
Java的枚举是一个特殊的类,一般表示一组常量。类似于26个字母、月份这种有几种固定的取值时,可以将其定义为枚举类型。
定义形式:
修饰符 enum 枚举类:基础类型{
枚举成员1,枚举成员2
}
public enum MyEnum {
Math,English,Chinese
}
注意事项
- 任意两个枚举成员不能具有相同的名称,且它的常数值必须在该枚举的基础类型的范围之内
- 多个枚举成员之间使用逗号分隔。
- 当有除了枚举成员之外的属性时,枚举成员必须在第一行并用分号结尾
- 枚举的基础类型可以不显示的声明,即枚举名后可以不加基础类型
- 如果没有显式地声明枚举的基础类型,那么意味着它所对应的基础类型是 int
补充:
- 在Java 中使用 enum 关键字来定义枚举类,其地位与 class、interface 相同
- 枚举类是一种特殊的类,它和普通的类一样,有自己的成员变量、成员方法、构造方法
- 枚举类的构造方法默认被 private 修饰(也只能被 private 修饰),所以无法从外部调用构造器(即 Enum 不能实例化),构造器只在构造枚举值时被调用
- 使用 enum 定义的枚举类默认继承了 java.lang.Enum 类(虽然没有显示继承),并实现了 java.lang.Seriablizable 和 java.lang.Comparable 两个接口
- 所有的枚举值都是 public static final 的,且非抽象的枚举类不能再派生子类
- 枚举类的所有实例(枚举值)必须在枚举类的第一行显式地列出,否则这个枚举类将永远不能产生实例。列出这些实例(枚举值)时,系统会自动添加 public static final 修饰,无需程序员显式添加
- 当定义一个枚举类型时,每一个枚举类型成员都可以看作是 Enum 类的实例,即枚举值是一个对象
- 与普通类一样,枚举类也可以实现一个或多个接口。枚举类实现接口时,同样要实现该接口的所有方法
二、使用
2.1 switch
public enum MyEnum {
Math,English,Chinese;
public static void main(String[] args) {
MyEnum myEnum = MyEnum.Math;
switch (myEnum){
case Math:
System.out.println("math");
break;
case Chinese:
System.out.println("Chinese");
break;
case English:
System.out.println("english");
break;
}
}
}
2.2 枚举类的常用方法
方法 | 用途 |
values() | 以数组形式返回枚举类型的所有成员 |
ordinal() | 获取枚举成员的索引位置 |
valueOf() | 将普通字符串转换为枚举实例 |
compareTo() | 比较两个枚举成员在定义时的顺序 |
public enum MyEnum {
Math,English,Chinese;
public static void main(String[] args) {
MyEnum[] myEnums = MyEnum.values();
for (int i = 0; i < myEnums.length; i++) {
System.out.println(myEnums[i] +"下标是:"+ myEnums[i].ordinal());
}
}
}
public enum MyEnum {
Math,English,Chinese;
public static void main(String[] args) {
System.out.println(Math.compareTo(English)); // -1
System.out.println(Math.compareTo(Chinese)); // -2
}
}
public enum MyEnum {
Math,English,Chinese;
public static void main(String[] args) {
System.out.println(MyEnum.valueOf("Math"));
System.out.println(MyEnum.valueOf("Math1"));
}
}
三、是否可以通过反射调用枚举的构造方法创建实例 不可以
public enum MyEnum {
Math("Math",1),English("English",2),Chinese("Chinese",3);
private String name;
private int key;
/**
* 当枚举对象有参数后,需要提供相应的构造函数
* 枚举的构造函数默认是私有的
* @param name
* @param key
*/
private MyEnum(String name,int key){
this.name = name;
this.key = key;
}
public static void main(String[] args) {
try {
Class<?> c1 = Class.forName("demo2.MyEnum");
Constructor<?> constructor = c1.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
MyEnum myEnum = (MyEnum)constructor.newInstance("Java",12);
System.out.println(myEnum);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
报异常:没有对应的构造方法
原因:自定义的枚举类,都是默认继承java.lang.Enum。因此,需要帮助父类进行构造。
解决方案1:适用super 不可行
解决方案2:枚举的构造函数虽然我们只写了两个,但是默认还添加了两个,因此一共有四个。默认添加的参数通过源码可以看到:
Constructor<?> constructor = c1.getDeclaredConstructor(String.class,int.class,String.class,int.class);
constructor.setAccessible(true);
MyEnum myEnum = (MyEnum)constructor.newInstance("Java",12,"父类的参数",1);
System.out.println(myEnum);
原因:
四、枚举的优缺点
- 优点:枚举常量更简单、更安全、枚举具有内置方法
- 缺点:枚举不可以继承、枚举无法扩展
五、用枚举实现单例模式
public enum TestEnum {
INSTANCE;
public TestEnum getInstance(){
return INSTANCE;
}
public static void main(String[] args) {
TestEnum testEnum1 = INSTANCE.getInstance();
TestEnum testEnum2 = INSTANCE.getInstance();
System.out.println(testEnum1 == testEnum2); // true
}
}