枚举类是一种特殊的类:
enum
定义的枚举类默认继承了 java.lang.Enum 类,而不是 Object 类,因此枚举类不能显示继承其他父类。final
修饰,因此枚举类不能派生子类。abstract
修饰枚举类,而不是使用 final 修饰。private
访问控制符修饰,如果省略了构造方法的访问控制符,则默认使用 private
修饰。public static final
修饰,无需显示的添加。values()
方法,以数组的形式返回该枚举的所有枚举值valueOf(String name)
方法,将普通的字符串转换为枚举实例,该字符串必须与枚举值名称相同由于所有的枚举类默认继承了 java.lang.Enum 类,因此可以使用该类中的所有方法。
方法 | 描述 |
---|---|
ordinal() | 返回枚举值在枚举类中的索引值,就是枚举值在枚举类中声明的位置,从0开始 |
name() | 返回枚举实例的名称,即定义枚举类时列出的所有枚举值之一 |
toString() | 返回枚举实例的名称,与name()方法相同,建议使用该方法 |
compareTo(E) | 用于与相同类型的枚举实例比较顺序。如果该枚举实例位于指定枚举实例之后,则返回正数;如果该枚举实例位于指定枚举实例之前,则返回负数;否则返回0 |
valueOf(Class |
静态方法,用于返回指定枚举类中指定名称的枚举值。名称必须与在枚举类中声明枚举值时所有的标识符完全匹配 |
枚举类的实例只能是枚举值,而不是随意通过 new 来创建的枚举类对象。
枚举类通常应该设计成不可变的类,也就是说,它的成员变量值不应该允许改变,因此建议将枚举类的成员变量使用 private final
修饰。
如果将所有成员变量都使用 final 来修饰,所以必须在构造方法中为这些成员变量指定初始值(或者在定义时显示指定默认值,或者在初始块中指定),因此应该为枚举类显示定义带参数的构造方法。
一旦为枚举类显示定义了带参的构造方法,列出枚举值时就必须对应的传入参数。
在枚举类中列出枚举值时,实际上就是调用构造方法创建枚举类对象,只是这里无需使用 new 关键字,也无需显示调用构造器。
public enum Gender {
MALE("男"), FEMALE("女");
//等同于如下两句,但是不可以使用如下两句进行声明
//private static final Gerder FEMALE = new Gender("女");
//private static final Gerder MALE = new Gender("男");
private final String name;
Gender(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
枚举类实现一个或多个接口时和普通类实现接口完全一样。
public interface GenderDesc {
void desc();
}
// 枚举类实现接口,并且重写接口中的方法
public enum Gender implements GenderDesc{
MALE("男"), FEMALE("女");
private final String name;
Gender(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public void desc() {
System.out.println("haha");
}
}
public class GenderTest {
public static void main(String[] args) {
Gender male = Gender.MALE;
male.desc(); //haha
Gender female = Gender.FEMALE;
female.desc(); //haha
}
}
如上所述,如果让枚举类来实现接口中的方法,则每个枚举值在调用接口中的方法时都有相同的行为方式。如果需要每个枚举值在调用方法时呈现出不同的行为方式,则可以让每个枚举值分别来实现该方法,每个枚举值有不同的实现,从而让不同的枚举值有不同的行为方式。
// 枚举值重写接口中方法,从而实现每个枚举值调用该方法有不同的实现
public enum Gender implements GenderDesc{
MALE("男") {
@Override
public void desc() {
System.out.println("male");
}
}, FEMALE("女") {
@Override
public void desc() {
System.out.println("female");
}
};
private final String name;
Gender(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class GenderTest {
public static void main(String[] args) {
Gender male = Gender.MALE;
male.desc(); //male
Gender female = Gender.FEMALE;
female.desc(); //female
}
}
在这种情况下,当创建FEMALE、MALE枚举值时,并不是直接创建了Gender枚举类的实例,而是相当于创建Gender匿名子类的实例。
编译上面的程序,可以看到生成了Gender.class、Gender$1.class、Gender$2.class三个文件,从而证明FEMALE、MALE实际上是Gender匿名子类的实例,而不是Gender的实例。
定义一个Operation枚举类,该枚举类有四个枚举值,PLUS,MINUS,TIMES,DIVIDE分别代表加减乘除,该枚举类需要定义一个eval方法来完成计算。
从枚举类实现接口来看,需要让枚举值对eval方法有不同的实现,因此可以考虑为Operation枚举类来定义一个eval抽象方法,然后让枚举值进行不同的实现。
public enum Operation {
PLUS {
@Override
public double evel(double x, double y) {
return x + y;
}
}, MINUS {
@Override
public double evel(double x, double y) {
return x - y;
}
}, TIMES {
@Override
public double evel(double x, double y) {
return x * y;
}
}, DIVIDE {
@Override
public double evel(double x, double y) {
return x / y;
}
};
//为枚举类定义抽象方法,该方法由不同的实例(枚举值)进行实现
public abstract double evel(double x, double y);
}
枚举类中定义抽象方法时,不能使用 abstract
关键字将枚举类定义成抽象枚举类(因为系统会自动给枚举类加上abstract关键字)。但是因为枚举类需要显示创建枚举值,而不是作为父类,所以定义每个枚举值时必须实现枚举类中的抽象方法,否则编译将会出错。