NIUCLOUD是一款SaaS管理后台框架多应用插件+云编译。上千名开发者、服务商正在积极拥抱开发者生态。欢迎开发者们免费入驻。一起助力发展! 广告
[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/