EffectiveJava——枚举和注解

枚举

第30条:用enum代替int常量

利用一组int常量来定义类的内部信息或行为称作int枚举模式,类似的还有String枚举模式
int枚举模式存在许多不足:
- 类型安全性和使用方便性没有任何帮助
- int枚举是编译时常量(不懂)
- int枚举常量的打印信息没有意义

String枚举模式的不足:
- 性能问题
- 初级程序员的硬编码,容易出错的书写错误(我也这么玩过-_-!)

所以应该使用枚举:
- 枚举是类型安全的
- 枚举还可以添加字段和方法
- 枚举提供了所有Object方法的高级实现,还实现了Comparable和Serializable
- 枚举随着时间的推移可以演变成为全功能的抽象

在枚举中定义抽象方法,避免枚举通过switch自身的枚举对象来选择行为。

多个枚举同时共享相同的行为时,考虑使用策略枚举(枚举的背部再定义枚举,每个枚举对象拥有一个背部枚举的对象,用内部枚举对象来封装外部枚举的行为),

与int常量相比,枚举的特点是装载和初始化有空间和时间的成本,除了受资源约束的设备(手机),在实践中不必考虑

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

所有枚举都有一个ordinal方法,返回自身在枚举常量中的位置。
永远不要根据枚举的序数导出与它相关的值,而是要将它保存在域中

public enum Ensemble{
   SOLO(1),DUET(2);

   private final int number;
   Ensemble(int size){
      this.number = size;
   }

}

第32条:用EnumSet代替位域

如果一个枚举的元素主要用在集合中,一般就使用int枚举模式,将2的不同倍数赋予每个常量:

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

    public void applyStyles(int styles){
       text.applyStyle(STYLE_BOLD | STYLE_ITALIC);
    }
}

这种表示法让你用|位运算符将几个常量合并到一个集合中,称作位域(bit field)

       EnumSet<Type> a = EnumSet.of(Type.A, Type.C);



    enum Type{
        A,B,C,D;
    }

位域有着所有int枚举常量的缺点,更高的代替方法是EumeSet;正式因为枚举类型要用在集合中,所以没有理由用位域来表示,如果EnumSet需要实现不可变性,考虑使用Collections.unmodifiableSet

第33条:用EnumMap代替序数索引

不是很懂-_-!

第34条:用接口模拟可伸缩的枚举

有时枚举被用作表示一组操作码,枚举可以实现接口,在接口中定义方法,而在具体的枚举中实现,可以很好的扩展之后的操作集。

虽然可以编写可扩展的枚举类型,却可以通过编写接口以及实现该接口的基础枚举类型,对它进行模拟。这样允许客户端编写自己的枚举实现接口。

注解

第35条:注解优先于命名模式

一般使用命名模式表明有些程序元素需要通过某种工具或者框架进行特殊处理,例如Junit的test类方法

命名模式的缺点:

  • 位子拼写会导致错误,而没有提示(test /tset)
  • 无法保证他们只用于特定的程序
  • 没有提供将参数值与程序元素关联起来的好方法,例如测试一个方法,当方法抛出一个异常时则表示测试成功,而没有有效的方法表示这个异常的类型

而注解没有这种缺点:

@Retention(RUNTIME)
@Target(ElementType.METHOD)
public @interface Test{
    Class<? extends Exception>[] values();
}

第36条:坚持使用Override注解

必须的

第37条:用标记接口定义类型

标记接口是没有方法声明的接口,而只是表明一个类实现了具有特种属性的接口。例如Serializable接口,表明对象可以被序列化。

标记接口胜过注解的两点:
- 标记接口定义的类型是由被标记类的实例实现的,标记注解则没有定义这样的类型。这允许在编译时捕捉异常
- 标记接口可以被更加精确的进行锁定

而标记注解胜过接口的最大优点在于:它可以通过默认的方式添加一个或多个注解类型元素,给已被使用的注解类型添加更多的信息,随这时间的推移,简单标识可以演变成更加丰富的注解类型。

如何区分使用

  • 如果标记是应用到程序元素而不是类或者接口,就必须使用标记注解
  • 如果标记值应用到类和接口上,就要问问自己,我要编写一个还是多个只接受有这种标记的方法?这个时候应该考虑使用标记接口
  • 考虑到未来需要添加更多的信息,或者标记要适用于已经使用了注解类型的框架,那么标记注解是正确的选择。

你可能感兴趣的:(EffectiveJava——枚举和注解)