如需转载,请标明原文出处以及作者

陈锐 RuiChen @kiwik

2021/01/26 10:04:17


Java枚举类型 Enum

什么是枚举类型?

The Java™ Tutorials:

An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.

变量必须为其预定义的值之一。

枚举:

public enum Direction {
    NORTH,
    SOUTH,
    EAST,
    WEST;

    public static void main(String[] args) {
        Direction val = Direction.EAST;
    }
}

常量集合:

public class Direction {
    public static final int NORTH = 0;
    public static final int SOUTH = 1;
    public static final int EAST = 2;
    public static final int WEST = 3;

    public static void main(String[] args) {
        Direction val = Direction.EAST;
    }
}

枚举类型的优势

  1. 代码量少。
  2. 更容易扩展。

    2.1 首字母表示方向: N, S, E, W

     public enum Direction {
         NORTH,
         SOUTH,
         EAST,
         WEST;
        
         public static void main(String[] args) {
             Direction val = Direction.EAST;
             val.name().charAt(0);
         }
     }
    

    2.2 多语言支持

     public enum Direction {
         NORTH("北"),
         SOUTH("南"),
         EAST("东"),
         WEST("西");
        
         final String chinese;
        
         Direction(String chinese) {
             this.chinese = chinese;
         }
        
         public static void main(String[] args) {
             Direction val = Direction.EAST;
             System.out.println(val.chinese);
         }
     }
    
  3. 高效的内置方法 name() ordinal() values() valueOf()

    3.1 name() : 常量的名

    3.2 ordinal() : 常量的位置,代表顺序。

    3.3 values() : 所有常量的集合,是一个有序的数组。

    3.4 valueOf() : 一个从名(字符串)到常量(Object)的转换,全局唯一。

  4. 声明即创建,单例,全局唯一,不允许通过new实例化。
    /**
     * Sole constructor.  Programmers cannot invoke this constructor.
     * It is for use by code emitted by the compiler in response to
     * enum type declarations.
     *
     * @param name - The name of this enum constant, which is the identifier
     *               used to declare it.
     * @param ordinal - The ordinal of this enumeration constant (its position
     *         in the enum declaration, where the initial constant is assigned
     *         an ordinal of zero).
     */
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }

Java内部表示可以理解为如下实现(单例模式):

public enum Direction {
    NORTH,
    public static final Direction NORTH = new Direction("NORTH", 0);
    SOUTH,
    EAST,
    WEST;
    ...
}

Java字节码:

 0 new #4 <org/apache/hadoop/fs/Direction>
 3 dup
 4 ldc #7 <NORTH>
 6 iconst_0
 7 invokespecial #8 <org/apache/hadoop/fs/Direction.<init>>
10 putstatic #9 <org/apache/hadoop/fs/Direction.NORTH>
13 new #4 <org/apache/hadoop/fs/Direction>
16 dup
17 ldc #10 <SOUTH>
19 iconst_1
20 invokespecial #8 <org/apache/hadoop/fs/Direction.<init>>
23 putstatic #11 <org/apache/hadoop/fs/Direction.SOUTH>
26 new #4 <org/apache/hadoop/fs/Direction>
...

enum and constructor :

  1. enum can contain constructor and it is executed separately for each enum constant at the time of enum class loading.
  2. We can’t create enum objects explicitly and hence we can’t invoke enum constructor directly.
  1. 可以用在switch块中。

枚举类型的坑

  1. ordinal字段由编译器根据枚举常量声明的位置顺序决定,且后续不能修改,也不能通过override改变行为。
public enum StorageType {

    // sorted by the speed of the storage types, from fast to slow
    RAM_DISK(true, true),
    NVDIMM(false, true), // <- add new, change following ordinal
    SSD(false, false),
    DISK(false, false),
    ARCHIVE(false, false),
    PROVIDED(false, false);
}

持久化EditLog时使用了ordinal,导致版本升级之后type错位。

protected void toXml(ContentHandler contentHandler) throws SAXException {
    XMLUtils.addSaxString(contentHandler, "SRC", src);
    XMLUtils.addSaxString(contentHandler, "STORAGETYPE",
            Integer.toString(type.ordinal()));
    XMLUtils.addSaxString(contentHandler, "DSQUOTA",
            Long.toString(dsQuota));
}
  1. ordinal可能变化,不能当作枚举常量的ID使用。


Published

26 January 2021

Category

Java

Tags