Java 枚举与接口

最后更新: 2024-06-05 02:14:10 +0800 +0800
tags: Enums | Java
原文以英文撰写。您正在阅读AI翻译版本。

枚举声明定义了一个包含固定实例集合的 final 类。每个 常量都是该类的实例;从概念上说,该类扩展 Enum<E>,其中枚举类型作为 E;任何用户定义的枚举都不能扩展其他类。 编译器提供 values() 和 valueOf(String),而 Enum 提供 名称、序号、比较和序列化规则。

接口与常量特定行为 #

枚举可以实现接口,实现可以由所有常量共享,也可以在常量特定的类体中提供。

java
enum Operation {
    ADD { int apply(int a, int b) { return a + b; } },
    SUBTRACT { int apply(int a, int b) { return a - b; } };

    abstract int apply(int a, int b);
}

每个常量特定类体都是编译器生成的匿名子类。因此,虚派发会选择对应的重写方法。外层枚举仍然是封闭集合,所以当策略在编译时已知时,这是一种有效的 Strategy 实现。如果扩展必须独立安装,应优先使用注入的接口实现。

常量特定类体可以实现枚举的抽象方法。当行为共享时,适合使用枚举级实现。除非生命周期确实应覆盖整个进程,否则不要在枚举常量中保存可变状态:枚举实例由定义它们的类加载器初始化一次。

身份、顺序与集合 #

枚举序列化会保留单例身份:反序列化按名称解析常量,而不是分配新实例。禁止使用 clone,也禁止通过反射构造枚举实例。使用 == 判断枚举身份,并避免持久化 ordinal(),因为插入或重新排列常量会改变它。只有当源代码级稳定性是明确契约时才持久化 name();对于长期保存的数据,外部代码字段更安全。

Enum.compareTo 按声明顺序排列常量。EnumSet 使用常量序号紧凑地表示集合,EnumMap 使用枚举键索引值。两者都要求使用一种枚举类型;当这一约束自然存在时,它们优于通用集合。

java
EnumSet<Operation> enabled = EnumSet.of(Operation.ADD);
EnumMap<Operation, String> labels = new EnumMap<>(Operation.class);
labels.put(Operation.ADD, "addition");

参考资料 #

评论

在 GitHub 上阅读或评论(发表评论需要登录)