第35条:用实例域代替序数

不要依赖枚举的 ordinal() 方法来获取与枚举常量关联的数值,而应该显式地定义实例域来存储这个值。

背景

在 Java 枚举中,每个常量都有一个 ordinal() 方法,返回它在枚举声明中的位置(从 0 开始)。

public enum Ensemble {
    SOLO, DUET, TRIO, QUARTET;
}

class Main {
    public static void main(String[] args) {
        System.out.println(Ensemble.SOLO.ordinal()); // 0
        System.out.println(Ensemble.DUET.ordinal()); // 1
        System.out.println(Ensemble.TRIO.ordinal()); // 2
        System.out.println(Ensemble.QUARTET.ordinal()); // 3
    }
}

有时候程序员会想用 ordinal() 来获取一个与枚举常量关联的数字(比如上面的例子中,SOLO 对应 1 个乐器,DUET 对应 2 个……),但这是一个非常危险且易出错的做法。

为什么不应该使用 ordinal()?

  1. 脆弱性:枚举常量的声明顺序一旦改变,ordinal() 的值就会变化,而依赖它的代码可能出错。例如,如果在 SOLO 前加一个新的常量,所有后续常量的序数都会改变。

  2. 可读性差:代码中使用 ordinal() 的数字含义不明确,很难维护。

  3. 不够灵活:有时你想关联的值并不是从 0 开始的连续整数,或者有间隔(比如 1, 2, 4, 8)。

正确做法:使用实例域

为枚举显式定义一个私有字段,通过构造函数赋值,并提供公共访问方法。

public enum Ensemble {
    SOLO(1), DUET(2), TRIO(3), QUARTET(4);

    private final int numberOfMusicians;

    Ensemble(int size) {
        this.numberOfMusicians = size;
    }

    public int getNumberOfMusicians() {
        return numberOfMusicians;
    }
}

何时可以使用ordinal

Enum规范中谈及ordinal方法时写道:“大多数程序员都不需要这个方法。它是设计用于像EnumSet 和EnumMap这种基于枚举的通用数据结构的。”除非你在编写的是这种数据结构,否则最好完全避免使用orainal方法。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐