6.8.1 相关概念

定义枚举类时,需要显式地列出所有枚举值,所有枚举值之间以英文逗号隔开,以英文分号作为结束。这些枚举值代表了该枚举类的所有可能实例。

枚举类不能被继承。

枚举类与普通类的区别:

  • 枚举类可以实现一个或者多个接口,默认继承了 java.lang.Enum 类,而不是继承 Object 类。其中 java.lang.Enum 类实现了 java.lang.Serializable 和 java.lang.Comparable 两个接口。
  • 枚举类的构造器只能使用 private 访问控制符,如果省略了,则默认使用 private 修饰。
  • 枚举类的所有实例必须在枚举类中显式列出,否则这个枚举类将永远都不能产生实例。列出实例时,系统会自动添加 public static final 修饰符,无需程序员显式添加。
  • 枚举类提供了一个 values 方法,用于遍历所有枚举值。

java.lang.Enum 类中提供了如下几个方法:

  • int compareTo(E o):如果该枚举对象位于指定枚举对象 o 之后,则返回正整数;如果在之前,则返回负整数;否则返回零。同一个枚举实例只能与相同类型的枚举实例进行比较。
  • String name():返回此枚举实例的名称,即定义该枚举值时的标识符。(优先使用 toString 方法)
  • int ordinal():返回枚举值在枚举类中的索引值,第一个枚举值的索引值为零。
  • public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name):返回指定枚举类中指定名称 name 的枚举值。名称 name 必须与枚举值的标识符完全匹配,不能有额外的空白字符。

定义枚举类例子:

public enum Gender {
    // 此处的枚举值调用了构造器
    MALE("男"),FEMALE("女");
    private String name;
    private Gender(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
	}
}

在枚举类中列出枚举值时,实际上就是调用构造器创建枚举类对象,只是这里无需使用 new 关键字,也无需显式调用构造器。

获取枚举类中枚举值的几种方法:

  • Gender male = Enum.valueOf(Gender.class, "MALE");
  • Gender male = Gender.valueOf("MALE");
  • Gender male = Gender.MALE;

6.8.2 实现接口的枚举类

若以下面的方式实现接口的抽象方法,则每个枚举类在调用该方法时,都有相同的行为方式,因为方法体完全相同。

interface GenderDesc {
    void info();
}

public enum Gender implements GenderDesc {
    MALE("男"),FEMALE("女");
    private String name;
    private Gender(String name){
        this.name = name;
    }
    
    public void info() {
        System.out.println("info()...");
    }
}

若以下面的形式实现接口的抽象方法,则可以实现每个枚举类调用该方法时,表现不同的形式。

public enum Gender implements GenderDesc {
    MALE("男") {
        public void info() {
            System.out.println("这个枚举值代表男性");
        }
    },
    FEMALE("女") {
        public void info(){
            System.out.println("这个枚举值代表女性");
        }
    };
    
    private String name;
    private Gender(String name){
        this.name = name;
    }
}

实际上,上面的代码在创建 MALE、FEMALE 枚举值时,并不是直接创建了 Gender 枚举类的实例,而是相当于创建了 Gender 的匿名子类的实例,可以像如下来理解:

Gender MALE = new Gender("男"){
    public void info () {
        System.out.println("这个枚举值代表男性");
    }
};

即 MALE、FEMALE 是 Gender 的匿名子类的实例。

6.8.3 包含抽象方法的枚举类

例子:

public enum Operation {
    PLUS {
        public double operate (double x, double y) {
            return x + y;
        }
    },
    MINUS {
        public double operate (double x, double y) {
            return x - y;
        }
    }
    
    // 为枚举类定义一个抽象方法,由不同的枚举值提供不同的实现
    public abstract double operate(double x, double y);
    
    public static void main(String[] args) {
        System.out.println(Operation.PLUS.operate(1, 2));
        System.out.println(Operation.MINUS.operate(4, 5));
    }
}

编译上面的程序会生成5个 class 文件:Operation 对应一个文件,另外四个分别对应四个匿名内部子类。

枚举类里定义抽象方法时无需显式使用 abstract 关键字将枚举类定义成抽象类。