Effective Java : 枚举和注解

30.使用enum代替int常量

以前的方案

在枚举出现前,都是 使用常量的方式,如

public static final int APPLE_FUJI = 0;  
public static final int ORANGE_NAVEL = 0;

这种方称为枚举常量,其弊端有:

  • 如果与枚举常量关联的 int 发生变化,则必须重新编译
  • 如果将枚举常量翻译成可打印的字符串,只能见到一个数字,没有太大的用处.

枚举方式

java 中的枚举本质上是 int值.

public enum Apple{FUJI}
public enum Apple{NAVEL}
  1. 枚举类基本想法 : 通过公有的 final域为 每个枚举常量 导出实例的类.
  2. 因为没有可访问的构造器, 因此枚举类型都是 final
  3. 因为 客户端 无法创建 枚举实例,也不能对其 进行扩展,因此枚举是 实例受控的,单例的泛型化
  4. 编译时类型安全,声明后取值一定是 枚举中的有效值 之一
  5. 通过复写 toString,可以将 枚举的值打印出来.
  6. 枚举可以添加任意的方法和域,并实现任意的接口

枚举的高级用法

  • switch,枚举中可以通过 switch(this)来根据不同的 做不同的操作,

示例 : Operation.java

  • 当然,上面种方式并不好,建议使用 特定于常量的方法实现(onstant-specific method implementation) Operation1.java

  • 可以通过构造函数传递参数,例如,示例:Operation.java, op 打印是调用toString打印出了+,-,*,/;

  • 利用策略枚举,可以用在更加安全,灵活的场景.如:书中的加班场景,每添加一种枚举常量就强制添加一种策略,示例代码:PayrollDay.java

总结

  1. switch 枚举 适合于 给外部的 枚举类型 增加特定于 常量的行为.
  2. 一般来说,枚举会 优先使用 comparable类型.而非 int类型
  3. 需要一组固定常量的时候就可以使用枚举.
  4. 枚举 装载和初始化的时候会有 空间和时间 的成本.

31.用实例域代替序数

简介

枚举的 ordinal()方法会返回枚举常量在类型中的数字位置,
但是尽量不要使用它,因为当重新排序后,会对客户端造成破坏.
正确的做法是,将他保存在 一个 实例域 中.

示例

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

    private final int numberOf;

    Ensemble(int _i) {
      this.numberOf = _i;
    }

    public int getNumberOf() {
      return numberOf;
    }
  }

32.使用enumset代替位域

int 枚举模式

public class Text {
    public static final int STYLE_BOLD = 1 << 0;
    public static final int STYLE_ITALIC = 1 << 1;
    public static final int STYLE_UNDERLINE = 1 << 2;
    public static final int STYLE_STRIKETHROUGH = 1 << 3;

    public void applyStyles(int styles) {
      //...
    }
  }

EnumSet模式

public class Text {
    public enum Style {
        BOLD, ITALIC, UNDERLINE, STRIKETHROUGH
    }
    // Any Set could be passed in, but EnumSet is clearly best
    public void applyStyles(Set