使用@IntDef和@StringDef代替Java枚举

最近看别人的代码,发现别人使用了@IntDef的注解,便上网搜了一圈记录下来。

定义

Google文档是这样说的

Use the @IntDef and @StringDef annotations so you can create enumerated annotations of integer and string sets to validate other types of code references. Typedef annotations ensure that a particular parameter, return value, or field references a specific set of constants. They also enable code completion to automatically offer the allowed constants.

就是可以通过@IntDef和@StringDef创建枚举注解来验证你的代码引用是否正确,编译器自动检查也会对此校验。

使用

一般我们用静态常量来替代枚举,比如一年四季,一周七天,九大行星,七大洲等这些固定的值:

1
2
3
4
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int AUTUMN = 3;
public static final int WINTER = 4;

但是这样写有些小问题,设置季节的时候可以设置任意int值,导致程序的健壮性不是很好。所以就引出了枚举:

1
2
3
enum Season {
SPRING, SUMMER, AUTUMN, WINTER
}

这样setSeason()就不会设置成其他值,只能是枚举中的其中一个值。
但是各种Android性能优化告诉我们,尽量少用枚举,枚举消耗的内存比定义成常量更多。(其实少用点枚举也没多大关系,只有在内存紧张的时候才会考虑),因此,谷歌就推出了@IntDef和@StringDef注解。

首先,加入依赖:

1
compile 'com.android.support:support-annotations:22.0.0'

然后,定义静态常量:

1
2
3
4
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int AUTUMN = 3;
public static final int WINTER = 4;

为这些常量声明@IntDef:

1
2
3
@IntDef({SPRING, SUMMER,AUTUMN,WINTER})
@Retention(RetentionPolicy.SOURCE)
public @interface Season {}

@Retention是Java里的注解内容,用于指定被修饰的Annotation可以保留多长时间:

  • RetentionPolicy.CLASS 默认值,编译器将把Annotation记录在class文件中。当运行Java程序时,JVM不再保留Annotation。
  • RetentionPolicy.RUNTIME 编译器将把Annotation记录在class文件中。当运行Java程序时,JVM也会保留Annotation。程序可以通过反射获取该Annotation信息。
  • RetentionPolicy.SOURCE Annotation只保留在源代码中,编译器直接丢弃这种Annotation。

接下来我们使用的时候:

1
2
3
4
5
6
7
8
9
10
@Season int currentDay ;

public void setCurrentDay(@Season int currentDay) {
this.currentDay = currentDay;
}

@Season
public int getCurrentDay() {
return currentDay;
}

这样就完成了,既不用枚举,常量也不会乱定义的问题。@StringDef用法一样,就是常量定义的是String类型。

参考

评论留言请点这里