WsztRush

Java枚举

用法

在JDK 1.5之前通常用final来定义各种常量,现在新加了枚举类型,最简单的用法如下:

enum Color {
    RED,
    GREEN
}

还可以像普通的类那样自己定义属性和方法:

enum Color {
    RED("red"),
    GREEN("green");
    String name;

    Color(String name) {
        this.name = name;
    }

    public String toString(){
        return name;
    }
}

甚至enum还可以去实现接口:

enum Color implements Comparable<Color> {
    RED,
    GREEN;
}

在使用的时候,枚举可以用来比较:

Color c = Color.RED;
if(c == Color.GREEN){
    // ...
}

也可以用来switch:

Color c = Color.RED;
switch (c) {
    case RED:
    case GREEN:
}

而且你可以很方便的变量一个枚举类型中所有的属性:

for (Color c : Color.values()) {
    System.out.println(c);
}

甚至在你只知道枚举的变量名的时候也能拿到对应的属性:

System.out.println(Color.valueOf("RED"));

看下来,枚举在定义常量上面做了不少友好的封装。

枚举VS常量

首先不同的枚举类是不同的类型,而你用final static修饰的一般都是int等基本类型,这样很难做类型检查,这算是Enum比较大的一个优势的优势,在写代码的时候不会传错参数:

public static void check(Color c){

}

当你传入其他类型参数时会编译出错。

enum到底是什么

在编译之后会有一个Color.class文件,使用javap查看:

final class Color extends java.lang.Enum implements java.lang.Comparable{
    public static final Color RED;
    public static final Color GREEN;
    public static Color[] values();
    public static Color valueOf(java.lang.String);
    static {};
}

该类继承自java.lang.Enum,然后通过javap -c Color来看初始化的代码:

static {};
  Code:
   0:   new     #4; //class Color
   3:   dup
   4:   ldc     #7; //String RED
   6:   iconst_0
   7:   invokespecial   #8; //Method "<init>":(Ljava/lang/String;I)V
   10:  putstatic       #9; //Field RED:LColor;
   13:  new     #4; //class Color
   16:  dup
   17:  ldc     #10; //String GREEN
   19:  iconst_1
   20:  invokespecial   #8; //Method "<init>":(Ljava/lang/String;I)V
   23:  putstatic       #11; //Field GREEN:LColor;
   26:  iconst_2
   27:  anewarray       #4; //class Color
   30:  dup
   31:  iconst_0
   32:  getstatic       #9; //Field RED:LColor;
   35:  aastore
   36:  dup
   37:  iconst_1
   38:  getstatic       #11; //Field GREEN:LColor;
   41:  aastore
   42:  putstatic       #1; //Field $VALUES:[LColor;
   45:  return

这里大家可能会对枚举switch有疑问,我们写代码来看下:

public class Test {
    public void func(Color c){
        switch(c){
            case RED:
            case GREEN:
        }
    }
}

然后用javap -c查看,得到:

public void func(Color);
  Code:
   0:   getstatic       #2; //Field Test$1.$SwitchMap$Color:[I
   3:   aload_1
   4:   invokevirtual   #3; //Method Color.ordinal:()I
   7:   iaload
   8:   lookupswitch{ //2
                1: 36;
                2: 36;
                default: 36 }
   36:  return
}

可以看到这里switch的其实还是enum类中的ordinal(int),和之前我们对switch的认识是一致的。