第 34 条:用 enum 代替 int 常量
当需要一组固定常量的时候,应该使用 enum 代替 int 常量。
第 35 条:用实例域代替序数
应该给 enum 添加 int 域,而不是使用 ordinal() 方法来导出与枚举关联的序数值。(几乎不应使用 ordinal() 方法,除非在编写像 EnumMap 这样的基于枚举的通用数据结构)
第36条:用 EnumSet 代替位域
- EnumSet 实现了 Set 接口
- 若枚举类型个数小于 64 个,则整个 EnumSet 就用单个 long 来表示,性能上比得上位运算
- 总而言之因为枚举类型要用在集合(Set)中,所以没有理由用位域来表示.
//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 不是可扩展的,在某些情况下,可能需要对枚举进行扩展,比如操作类型(±*/等),就可以考虑:
- 定义一个接口,比如
public interface Operation{…};
- 使枚举继承接口:比如
public enum BasicOperation implements Operation{…}
- 使用时的 API 写成接口(比如,
T extends Enum & Operation)
,而不是实现(比如BasicOperation
) - 当需要扩展
BasicOperation
枚举时,就可以另写一个枚举,且 implements 接口Operation
第 39 条:注解优先于命名模式
第 40 条:坚持使用 Override 注解
第 41 条:用标记接口实现类型
标记接口可以在编译时就检查到相应的类型问题,而标记注解则要到运行时。
- 如果标记是应用到任何程序元素而不是类或者接口,就必须使用注解. 因为只有 类和接口可以用来实现或者扩展接口
- 如果标记只应用给类和接口,就应该 优先使用标记接口而非注解