05 枚举和注解(34-41)

Wu Jun 2019-01-17 23:10:05
05 Java > 02 Effective Java

第 34 条:用 enum 代替 int 常量

当需要一组固定常量的时候,应该使用 enum 代替 int 常量。

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

应该给 enum 添加 int 域,而不是使用 ordinal() 方法来导出与枚举关联的序数值。(几乎不应使用 ordinal() 方法,除非在编写像 EnumMap 这样的基于枚举的通用数据结构)

第36条:用 EnumSet 代替位域

//WRONG
public class Text{
    private static final int STYLE_BOLD = 1 << 0;
    private static final int STYLE_ITALIC = 1 << 1;
    private static final int STYLE_UNDERLINE = 1 << 2;
    
    public void applyStyles(int styles) {...}
}
//use
text.applyStyles(STYLE_BOLD | STYLE_ITALIC);

//RIGHT
public class Text{
    public enum Style{STYLE_BOLD, STYLE_ITALIC, STYLE_UNDERLINE}
    
    public void applyStyles(Set<Style> styles) {...} 
}
//use
text.applyStyles(EnumSet.of(STYLE_BOLD, STYLE_ITALIC));

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

序数索引是指依赖于枚举成员在枚举中的序数来进行数组索引

应该使用 EnumMap 来实现,EnumMap 内部是采用数组实现的,具有 Map 的丰富功能和类型安全以及数组的效率

Map<Plant.Type, Set<Plant>> plants = new EnumMap<Plant.Type, Set<Plant>>(Plant.Type.class); 

for(Plant.Type type : Plant.Type.valuse()){
    plants.put(type, new HashSet<Plant>);
}

for(Plant p : garden){
    plants.get(p.type).add(p);
}

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

由于在 Java 中 enum 不是可扩展的,在某些情况下,可能需要对枚举进行扩展,比如操作类型(±*/等),就可以考虑:

  1. 定义一个接口,比如public interface Operation{…};
  2. 使枚举继承接口:比如public enum BasicOperation implements Operation{…}
  3. 使用时的 API 写成接口(比如,T extends Enum & Operation),而不是实现(比如BasicOperation
  4. 当需要扩展BasicOperation枚举时,就可以另写一个枚举,且 implements 接口Operation

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

第 40 条:坚持使用 Override 注解

第 41 条:用标记接口实现类型

标记接口可以在编译时就检查到相应的类型问题,而标记注解则要到运行时。