抛弃枚举, 在android中一个更好的方法替代他.
起因
阅读原文
当我们想从一些预定义的常量中使用一个变量我们能怎么做. 我可以声明常量并给他们赋值. 我们假设某一个值是表示今天,他可以从周日到周六有不一样的值来指定,我们在java中可以这样使用整数型常量.
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; }}
问题
这段代码看似已经实现功能, 但是有问题存在的因为我可以设置任何的整数型的值给当前的currentDay.
obj.setCurrentDay(100);
方案1 使用Enum
这样即使我们设置了超出了currentDay没有实际意义值得时候, 编译器却没有给我们任何的提示. 然后在 switch语句中将错过这些值. 所以java给了我们一个解决方案就是使用枚举(Enum)和Enumerarion. 我们可以使用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,set只接收Enum类型, 而Enum里面有什么使我们预先定义好的.这样就解决了之前出现的问题.这是一个好的解决方案.所以我们应该在以后根据场景使用它, 但是在Android中还是会有些问题的
方案2 使用android特有的魔术变量注解替代Enum
Enum in Android 枚举Enum在java中是一个完整的类. 而枚举中的每一个值在枚举类中都是一个对象. 所以在我们使用时枚举的值将比整数常量消耗更多的内存. 当我们使用枚举在安卓应用中, 如果我们的程序本身内存消耗就比较大,或者是一个游戏的应用程序. 那么我们最好使用常量来替代枚举. 但之前的问题仍然存在.
那么有什么好的办法么?
当然, Android 支持注解库中有一些好用的annotation helper 我们可以使用它们来解决我们之前的问题(在编译代码时期).
IntDef
和StringDef
是两个魔术变量注解. 使用这个两个来替代之前使用的Enum. 它将帮助我们在编译代码时期像Enum那样选择变量的功能. 接下来我们来使用IntDef
来替换Enum看一下.
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; }}
现在我们不能直接用一个int值赋值给currentDay变量, 或者在set赋值的时候只能传入currentDay变量被注解所规定的魔术注解IntDef
中的常量引用(而不是引用对应的引用值). 当我们使用赋一些没有意义的值时, 编译器将给我们一些警告让我们修改.
如果我们使用过的是Android Studio开发的话, IDE将给我们关于如果使用的建议.
创建步骤
我们可以拆解一下步骤.
首先如果想要这个特证,你应该添加 support-annotations library 到你的项目中去, 如果你使用AS,可以使用gradle的依赖.
dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') ... compile 'com.android.support:support-annotations:22.0.0'}
如果你的项目已经依赖这个:com.android.support:appcompat-v7, 那或许不需要单独添加上述库的依赖
1.首先声明常量
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;
2.创建一个注解,声明魔术变量@IntDef(或者@StringDef其实后面传入的为String类型常量)并给其添加想预定义的int常量
@IntDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})@Retention(RetentionPolicy.SOURCE)public @interface WeekDays {}
3.给变量currentDay使用注解
@WeekDays int currentDay ;//这时currentDay 不会接收weekDays以外的所有值, 即使是IntDef中常量名对应的值也不可以, 只能使用weekDays常量引用
4.如果我们要声明currentDay的setter和getter,可以这样使用来限制问题
public void setCurrentDay(@WeekDays int currentDay) { this.currentDay = currentDay;}@WeekDayspublic int getCurrentDay() { return currentDay;}
如果你想了解更多关于注解支持库的介绍,come here (自备梯子).