Java枚举学习
说明:作者才疏学浅,本文仅为作者学习笔记,如果帮助到后来者,不胜荣幸,另外本文参考了其他大佬的讲解和代码,链接在下方贴出
参考链接:
Java 枚举(enum) 详解7种常见的用法
参深入理解Java枚举类型(enum)
借助一个常见的枚举例子,了解一下枚举的基本概念
enum Day {
MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
枚举是什么
枚举是java5提供的新特性之一,我们可以在一定程度上把它理解成是“类”这种类型,但是它比“类”这种数据类型又多了一些约束,因此可以理解为枚举是一种特殊的类类型。通过javac命令可以看出,enum编译后的确可以得到class文件,由此证明,我们编写的枚举类经过编译后,编译器会帮我们生成一个与枚举相关的类。
枚举里面的东东是什么
上面说到,枚举可以理解成一种特殊的类类型。其中所定义的MONDAY等,这些量叫做枚举常量,其数据类型就是枚举类Day,也就是说,这些枚举常量其实就是相应的枚举类(此处是Day)的实例化对象而已,这里要注意这些实例化对象都是static final修饰的,即都是常量,不可以被改变。这里附上大佬将枚举类的class文件反编译得到的结果,应该可以更好地理解:
//反编译Day.class
final class Day extends Enum
{
//编译器为我们添加的静态的values()方法
public static Day[] values()
{
return (Day[])$VALUES.clone();
}
//编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
public static Day valueOf(String s)
{
return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);
}
//私有构造函数
private Day(String s, int i)
{
super(s, i);
}
//前面定义的7种枚举实例
public static final Day MONDAY;
public static final Day TUESDAY;
public static final Day WEDNESDAY;
public static final Day THURSDAY;
public static final Day FRIDAY;
public static final Day SATURDAY;
public static final Day SUNDAY;
private static final Day $VALUES[];
static
{
//实例化枚举实例
MONDAY = new Day("MONDAY", 0);
TUESDAY = new Day("TUESDAY", 1);
WEDNESDAY = new Day("WEDNESDAY", 2);
THURSDAY = new Day("THURSDAY", 3);
FRIDAY = new Day("FRIDAY", 4);
SATURDAY = new Day("SATURDAY", 5);
SUNDAY = new Day("SUNDAY", 6);
$VALUES = (new Day[] {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
});
}
}
Enum类
从上面反编译的文件中我们可以看出,编译器为我们生成的枚举相关的类是继承于Enum这个类的,Enum是所有java枚举类型的公共基本类,它是一个抽象类。接下来学习一下这个类中的核心方法。
返回类型 | 方法名称 | 方法说明 |
---|---|---|
String | name() | 返回此枚举常量的名称,在其枚举声明中对其进行声明 |
String | toString() | 返回枚举常量的名称,它包含在声明中 |
int | ordinal() | 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零) |
int | compareTo(E o) | 比较此枚举与指定对象的顺序 |
boolean | equals(Object other) | 当指定对象等于此枚举常量时,返回 true。 |
static<T extends Enum> T static | valueOf(Class enumType, String name) | 返回带指定名称的指定枚举类型的枚举常量。 |
Class<?> | getDeclaringClass() | 返回与此枚举常量的枚举类型相对应的 Class 对象 |
其中name和toString方法,可以得到枚举常量的名称,ordinal方法,可以返回枚举常量的序数,注意下标是从0开始,compare方法是比较两个枚举常量的序数大小,equals是枚举常量的比较。关于valueOf方法,可以根据枚举类型和名称返回指定的枚举常量,最后的getDeclaringClass方法后面学到再看。
values与valueOf
回过头再看反编译得到的代码,枚举相关的类继承了Enum这个抽象类之后,编译器又为其生成了一个values方法,并重载了继承而来的valueOf方法。valueOf方法的功能没有改变,依旧是返回相关的枚举常量,只不过这时候只需要传递常量的名称为参数即可,不需要指定哪个枚举类中的了。
而新生成的values方法也并不神秘,他是一个static方法,可以以数组形式返回枚举中所有的枚举常量。
//例如
Day[] ds=Day.values();
Day day = Day.valueOf("MONDAY");
既然如此,那么问题来了,当枚举类型向上转型为Enum类型时,values方法就不能用了,那怎么获取所有的枚举常量呢?
哈哈哈,当然有解决办法啦,我们知道Java中所有的类都有一个共同的老大Class,枚举类型虽然是一种特殊的类类型,但是依然被Class所折服,在Class中,有一个专门为枚举类型准备的方法——getEnumConstants(),这个方法可以返回枚举的所有常量,而如果其不是枚举类型,则返回null。而且,我们还可以使用isEnum方法判断其是否为枚举类型,因此,大佬写出了如下代码:
Class<?> clasz = e.getDeclaringClass();
if(clasz.isEnum()) {
Day[] dsz = (Day[]) clasz.getEnumConstants();
System.out.println("dsz:"+Arrays.toString(dsz));
}
/**
输出结果:
dsz:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]
*/
通过这种方法,我们又可以获得所有的枚举常量啦。
经过上述学习,我们基本可以把枚举当成类去思考。下面记录枚举的常见用法:
1. 用枚举来表示类似含义的常量
//其实就是第一个例子
enum Day {
MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
2. 用枚举作为switch-case的支持类型
switch可以支持int ,char ,和枚举
enum Signal {
GREEN, YELLOW, RED
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch (color) {
case RED:
//操作。。。
break;
case YELLOW:
//操作。。。
break;
case GREEN:
//操作。。。
break;
}
}
}
3. 向枚举中添加新方法
我们知道,枚举常量是由编译器根据我们的定义生成的实例化对象,生成过程中使用的是默认的构造函数,其实,我们也可以自定义每个枚举类型的构造函数,例如:
public enum Color {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
//普通方法
}
注意:各个枚举常量的构造方法必须写在最前面,用逗号分隔开,最后一个写分号。然后在下面可以定义枚举类的属性,构造方法和普通方法
4. 方法覆盖
上面已经说了,枚举会被编译器转变成相关的类,那么我们就可以重写其原有的方法,即方法覆盖,例如,重写toString()
public enum Color {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
//覆盖方法
@Override
public String toString() {
return this.index+"_"+this.name;
}
}
5. 实现接口
枚举所生成的类,已经继承了Enum类,因此,我们只能通过接口来对枚举进行扩展
public interface Interface1{
//......
}
public enum Day implements Interface1{
//........
}
下面这两种用法还没有学,好像涉及到更难的东东,先行保留。。。。。