[TOC]
#Java 枚举 和 Android IntDef/StringDef 注解
##翻译自原文:[Java Enum and Android IntDef/StringDef Annotation]
##使用 Integer 常量
当我们想要一个变量 x,并且它的值来自于一些已经定义好的常量。那么我们可以这样做:我们可以先定义一些常量,然后把这些常量的值赋值给 x 。现在我们假设 x 就是 `currentDay`,以及 x 可以拥有星期一到星期日的 7 个值,那么我们可以在 Java 中定义 `Integer`常量,然后这样写:
~~~
public class Main {
public static final int SUNDAY = 0;
public static final int MONDAY = 1;
public static final int TUESDAY = 2;
public static final int WEDNESDAY = 3;
public static final int THURSDAY = 4;
public static final int FRIDAY = 5;
public static final int SATURDAY = 6;
private int currentDay = SUNDAY;
public static void main(String[] args) {
// TODO Auto-generated method stub
Main obj = new Main();
obj.setCurrentDay(WEDNESDAY);
int today = obj.getCurrentDay();
switch (today) {
case SUNDAY:
System.out.println("Today is SUNDAY");
break;
case MONDAY:
System.out.println("Today is MONDAY");
break;
case TUESDAY:
System.out.println("Today is TUESDAY");
break;
case WEDNESDAY:
System.out.println("Today is WEDNESDAY");
break;
case THURSDAY:
System.out.println("Today is THURSDAY");
break;
case FRIDAY:
System.out.println("Today is FRIDAY");
break;
case SATURDAY:
System.out.println("Today is SATURDAY");
break;
default:
break;
}
}
public void setCurrentDay(int currentDay) {
this.currentDay = currentDay;
}
public int getCurrentDay() {
return currentDay;
}
}
~~~
##使用枚举
上面的代码中存在一个问题:我可以将任何 `Integer` 类型的值赋值给 `currentDay`,例如`obj.setCurrentDay(100);`
编译器不会提示任何错误,而且 `switch` 将匹配不到所对应的 `case`,这种情况是我们不希望看到的,不过 Java 提供了一个解决的方法:**Enum**,就是枚举。如果我们使用枚举重写上面的代码:
~~~
public class Main {
public enum WeekDays {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}
private WeekDays currentDay = WeekDays.SUNDAY;
public static void main(String[] args) {
// TODO Auto-generated method stub
Main obj = new Main();
obj.setCurrentDay(WeekDays.WEDNESDAY);
WeekDays today = obj.getCurrentDay();
switch (today) {
case SUNDAY:
System.out.println("Today is SUNDAY");
break;
case MONDAY:
System.out.println("Today is MONDAY");
break;
case TUESDAY:
System.out.println("Today is TUESDAY");
break;
case WEDNESDAY:
System.out.println("Today is WEDNESDAY");
break;
case THURSDAY:
System.out.println("Today is THURSDAY");
break;
case FRIDAY:
System.out.println("Today is FRIDAY");
break;
case SATURDAY:
System.out.println("Today is SATURDAY");
break;
default:
break;
}
}
public void setCurrentDay(WeekDays currentDay) {
this.currentDay = currentDay;
}
public WeekDays getCurrentDay() {
return currentDay;
}
}
~~~
现在我们有了类型的限制,`currentDay` 只能接受 `WeekDays` 类型的值,不能接受其他任何值。这比使用 `Integer`常量好了很多,所以我们会认为:我们应该多使用枚举来代替 `Integer` 常量。但是**在 Android 中使用枚举**,又会产生一个新的问题:因为 Enum 在 Java 中是一个完整的类,每个枚举类的值都是枚举类的对象,所以使用枚举要比我们之前使用 `Integer` 常量消耗更多的内存。不过即使是在老的 Android 设备上(系统版本<=2.2),关于使用枚举的一些性能问题也已经通过 JIT 编译器解决了([简单了解JIT]),现在我们是可以在 Android 应用程序中使用枚举的,但是如果我们的应用程序本身就需要消耗很多内存,或者我们的应用程序是一个游戏应用,那么我们最好使用 `Integer` 常量来代替枚举,但是这样做的话,文章开头提到的问题就又会出现,为了解决这个问题,我们可以采用 Android 提供的一种方法。
##使用 Android 注解支持库
Android 提供的方法是:使用 `com.android.support:support-annotations` ,这个官方的注解支持库中包含了许多很好的注解,可以帮助我们在编译的时候就找到错误。`IntDef` 和 `StringDef` 是包含在库中的两个关于常量的注解,我们可以用来代替**枚举**,它们可以帮助我们在编译时检查变量的赋值,就像枚举一样。下面的代码演示了如何通过 `IntDef` 来代替枚举。
~~~
public class MainActivity extends Activity {
public static final int SUNDAY = 0;
public static final int MONDAY = 1;
public static final int TUESDAY = 2;
public static final int WEDNESDAY = 3;
public static final int THURSDAY = 4;
public static final int FRIDAY = 5;
public static final int SATURDAY = 6;
@IntDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})
@Retention(RetentionPolicy.SOURCE)
public @interface WeekDays {}
@WeekDays int currentDay = SUNDAY;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setCurrentDay(WEDNESDAY);
@WeekDays int today = getCurrentDay();
switch (today){
case SUNDAY:
break;
case MONDAY:
break;
case TUESDAY:
break;
case WEDNESDAY:
break;
case THURSDAY:
break;
case FRIDAY:
break;
case SATURDAY:
break;
default:
break;
}
}
public void setCurrentDay(@WeekDays int currentDay) {
this.currentDay = currentDay;
}
@WeekDays
public int getCurrentDay() {
return currentDay;
}
}
~~~
现在我们只能把 `@IntDef` 中的值赋值给 `currentDay` 和 `today`,其他的值都不行,同时编译器也会进行检查,并且提示错误。如果我们使用 Android Studio,那么当我们在写赋值代码的时候, IDE 也会提示 `@IntDef` 中的值作为建议。上面的代码是已经全部写好了的,现在我们来一步步演示,如何使用 `@IntDef`。
* 首先定义这些常量:
~~~
public static final int SUNDAY = 0;
public static final int MONDAY = 1;
public static final int TUESDAY = 2;
public static final int WEDNESDAY = 3;
public static final int THURSDAY = 4;
public static final int FRIDAY = 5;
public static final int SATURDAY = 6;
~~~
* 接着通过这些常量来定义一个 `@IntDef` 注解,并且用 `@IntDef` 注解来修饰我们自定义的注解:
~~~
@IntDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})
@Retention(RetentionPolicy.SOURCE)
public @interface WeekDays {}
~~~
* 设置一个使用 `@WeekDays` 修饰的变量,那么这个变量只能被 `@IntDef` 中的值所赋值,其他的值都不能赋值给它,我们可以像下面这样定义:
`@WeekDays int currentDay ;`
* 如果现在把其他的值赋值给 `currentDay`,那么编译器就会提示错误。下面的代码演示了如何用 `@WeekDays` 来修饰方法中的参数和返回值:
~~~
public void setCurrentDay(@WeekDays int currentDay) {
this.currentDay = currentDay;
}
@WeekDays
public int getCurrentDay() {
return currentDay;
}
~~~
* **@StringDef** 使用的方式是一样的:
~~~
public class MainActivity extends Activity {
public static final String SUNDAY = "sunday";
public static final String MONDAY = "monday";
public static final String TUESDAY = "tuesday";
public static final String WEDNESDAY = "wednesday";
public static final String THURSDAY = "thursday";
public static final String FRIDAY = "friday";
public static final String SATURDAY = "saturday";
@StringDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})
@Retention(RetentionPolicy.SOURCE)
public @interface WeekDays {}
@WeekDays String currentDay = SUNDAY;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setCurrentDay(WEDNESDAY);
@WeekDays String today = getCurrentDay();
switch (today){
case SUNDAY:
break;
case MONDAY:
break;
case TUESDAY:
break;
case WEDNESDAY:
break;
case THURSDAY:
break;
case FRIDAY:
break;
case SATURDAY:
break;
default:
break;
}
}
public void setCurrentDay(@WeekDays String currentDay) {
this.currentDay = currentDay;
}
@WeekDays
public String getCurrentDay() {
return currentDay;
}
}
~~~
为了使用这两个注解,你必须添加 `com.android.support:support-annotations` 这个库到你的项目中,如果你使用 Android Studio 的话,可以在你的 Gradle 中添加依赖:
~~~
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
...
compile 'com.android.support:support-annotations:24.2.0'
}
~~~
> 注:如果您使用 appcompat 库,则无需添加 support-annotations 依赖项。因为 appcompat 库已经依赖注解库,您可以访问相关注解。---来自 [Android 文档:添加支持注解库依赖项]
[Android 文档:添加支持注解库依赖项]:https://developer.android.com/studio/write/annotations.html#adding-library
[简单了解JIT]:http://blog.dontcareabout.us/2013/03/jit-compiler.html
[Java Enum and Android IntDef/StringDef Annotation]:https://noobcoderblog.wordpress.com/2015/04/12/java-enum-and-android-intdefstringdef-annotation/