跳转至

枚举类型

枚举类型的基本特性

  • 创建枚举类型时,编译器会自动生成一个辅助类,这个类自动继承自java.lang.Enum,包含的功能有:
    • ordinal():返回一个从0开始的int值,代表每个枚举实例的声明顺序
    • 可以直接使用==来比较枚举实例(equals()hashCode()方法编译器自动生成)
    • 实现了Comparable接口,可以直接进行比较
      • 自动包含了compareTo()方法
    • 实现了Serializable接口
    • getDeclareingClass()可以得到该枚举实例所属的外部包装类
    • name()方法返回枚举实例被声明的名称
      • 使用toString()方法可以达到同样的目的
    • valueOf()Enum类中的静态方法,它根据传入的String,返回名称与该String匹配的枚举类型
      • 如果匹配的实例不存在,则抛出异常
  • 通过static import将所有的枚举类型标识符都引入本地的命名空间
    • 这样的方式可以不需要显式的使用枚举类型来限定,可以直接在代码中使用
      package enums;  
      import static enums.SpicinessEnum.*;  
      
      public class Burrito2 {  
        SpicinessEnum degree;  
        public Burrito2(SpicinessEnum degree) {  
          this.degree = degree;  
        }  
        @Override public String toString() {  
          return "Burrito is "+ degree;  
        }  
        public static void main(String[] args) {  
          System.out.println(new Burrito2(NOT));  
          System.out.println(new Burrito2(MEDIUM));  
          System.out.println(new Burrito2(HOT));  
        }  
      }  
      /* Output:  
      Burrito is NOT  
      Burrito is MEDIUM  
      Burrito is HOT  
      */
      

在枚举类型中增加自定义的方法

对于枚举类型来说,除了无法继承(final)它以外,可以将其看做一个普通的类。 这意味着你可以在里面增加自定义的方法,甚至是一个main()方法 但是实例必须在方法之前定义 - 如果想要增加自定义方法,则必须在方法之前定义枚举实例的序列 - 构造方法: - 构造方法的类型必须是包级或者是private:在枚举定义完成之后,编译器不会允许使用它来创建任何新的类型 - 重载枚举类型中的方法与重载任何普通类的方法一致

switch语句中使用枚举

由于enum内部已经构建了一个整型序列,枚举类型可以非常方便的用在switch语句中,并且可以通过ordinal()方法来得到枚举实例的顺序

Signal color = Signal.RED;  
public void change() {  
  switch(color) {  
    // Note you don't have to say Signal.RED  
    // in the case statement:    case RED:    color = Signal.GREEN;  
         break;    case GREEN:  color = Signal.YELLOW;  
         break;    case YELLOW: color = Signal.RED;  
         break;  }  
}
编译器不会因为该switch中没有default而报错,因此在使用switch时必须小心,确保手动覆盖了所有分支。 但是,如果在case语句中调用了return,而没有编写default,编译器会报错

values()方法

  • values()方法是由编译器添加的一个静态方法
  • 由于values()方法是由编译器在枚举类的定义中插入的一个静态方法,因此如果将其向上转型为Enum,则无法使用该方法
    • 可以通过其Class对象的getEnumConstant()来得到enum的实例

实现,而不是继承

由于所有的enum类都默认继承java.lang.Enum,而java不支持多继承,因此无法自行通过继承方式创建一个枚举对象 不过可以通过实现接口的方式

// enums/cartoons/EnumImplementation.java  
// (c)2021 MindView LLC: see Copyright.txt  
// We make no guarantees that this code is fit for any purpose.  
// Visit http://OnJava8.com for more book information.  
// An enum can implement an interface  
// {java enums.cartoons.EnumImplementation}  
package enums.cartoons;  
import java.util.*;  
import java.util.function.*;  

enum CartoonCharacter  
implements Supplier<CartoonCharacter> {  
  SLAPPY, SPANKY, PUNCHY,  
  SILLY, BOUNCY, NUTTY, BOB;  
  private Random rand =  
    new Random(47);  
  @Override public CartoonCharacter get() {  
    return values()[rand.nextInt(values().length)];  
  }  
}  

public class EnumImplementation {  
  public static <T> void printNext(Supplier<T> rg) {  
    System.out.print(rg.get() + ", ");  
  }  
  public static void main(String[] args) {  
    // Choose any instance:  
    CartoonCharacter cc = CartoonCharacter.BOB;  
    for(int i = 0; i < 10; i++)  
      printNext(cc);  
  }  
}  
/* Output:  
BOB, PUNCHY, BOB, SPANKY, NUTTY, PUNCHY, SLAPPY, NUTTY,  
NUTTY, SLAPPY,  
*/

随机选择

使用接口来组织枚举

可以在一个接口内对原宿进行分组,然后基于这个接口生成一个枚举,通过这样的方式来实现元素的分类

// enums/menu/Food.java  
// (c)2021 MindView LLC: see Copyright.txt  
// We make no guarantees that this code is fit for any purpose.  
// Visit http://OnJava8.com for more book information.  
// Subcategorization of enums within interfaces  
package enums.menu;  

public interface Food {  
  enum Appetizer implements Food {  
    SALAD, SOUP, SPRING_ROLLS;  
  }  
  enum MainCourse implements Food {  
    LASAGNE, BURRITO, PAD_THAI,  
    LENTILS, HUMMUS, VINDALOO;  
  }  
  enum Dessert implements Food {  
    TIRAMISU, GELATO, BLACK_FOREST_CAKE,  
    FRUIT, CREME_CARAMEL;  
  }  
  enum Coffee implements Food {  
    BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,  
    LATTE, CAPPUCCINO, TEA, HERB_TEA;  
  }  
}
- 实现接口是唯一可以子类化枚举的方式,因此所有嵌套在Food中的枚举类型都实现了Food接口 - 对于每个实现了Food接口的枚举类型,都可以向上转型为Food类型 - 另一种更简洁的方法是直接在枚举中嵌套枚举