ENUM是什么,为什么使用它
Enum
是Java中包含固定常量的数据类型。当需要使用预先定制的几个值,这几个值表示一些数据类,这时我们可以用ENUM
。在一些可能的值中取一个值时很适合用Enums
。例如:
public enum Season
{
WINTER, SPRING, SUMMER, FALL
}
不用Integer
或String
常量,我们一般用ENUM
可以在编译时进行检查,避免传入不合法的参数。
使用ENUM的缺陷
ENUM
中的每一个值都是一个Object
,它的每个声明都会占用运行时的部分内存以便能够引用到这个Object
。因此ENUM
的值会比对应的Integer
和String
所占用的内存多。在Android之前的版本中(<=2.2),存在着关于ENUM
引起的性能问题,这个问题在JIT编译器中解决了。
添加一个ENUM
将会增大最终的DEX文件(Integer
常量的13倍大)。并且会引起运行时的过度开销,你的应用也会占用更多的空间。
因此过度在Android开发中使用ENUM
将会增大DEX大小,并会增大运行时的内存分配大小
如果你的应用是使用了许多的ENUM
,那么使用Integer
或者String
常量会更好。但问题仍然存在…
解决办法
Android 提供了注解库,其中有TypeDef注解。这些注解能够确保一个特定的参数,返回值或者字段能够在特别一组常量中引用一个。它们能确保自动完成允许的常量中选择一个。
IntDef
和StringDef
是两个神奇的注解常量,可以用来替代Enum
的使用。这些注解能够帮助我们在编译时对变量赋值进行检查。
如何使用?
我们从一个简单的例子中去明白如何使用。下面的代码段是关于ConstantSeason
类的。
public class ConstantSeason {
public static final int WINTER = 0;
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int FALL = 3;
public ConstantSeason(int season) {
System.out.println("Season :" + season);
}
public static void main(String[] args) {
// Here chance to paas invalid value
ConstantSeason constantSeason = new ConstantSeason(5);
}
}
不幸的是,这里不法确保用户能够输入正确的值–这样使用没有类型保证。
同时使用ENUM
来实现将会是如下:
public class EnumSeason {
public EnumSeason(Season season) {
System.out.println("Season :" + season);
}
public enum Season {
WINTER, SPRING, SUMMER, FALL
}
public static void main(String[] args) {
EnumSeason enumSeason = new EnumSeason(Season.SPRING);
}
}
现在让我们瞧瞧神奇的注解常量是如何解决的。
添加支持注解的依赖到你的项目中,需要在build.gradle文件中的依赖块中添加: dependencies { compile 'com.android.support:support-annotations:24.2.0' }
声明常量和@IntDef
// Constants
public static final int WINTER = 0;
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int FALL = 3;
// Declare the @IntDef for these constants
@IntDef({WINTER, SPRING, SUMMER, FALL})
@Retention(RetentionPolicy.SOURCE)
public @interface Season {}
这里TypeDef注解使用了@interface
来声明新的枚举注解类型。其中@IntDef
和@StringDef
注解以及@Retention
标注了新的注解,目的是定义这个枚举类型。而@Retentino(RententionPolicy.SOURCE)
注解告诉编译器在生成.class文件时不保留枚举注解数据。
因此实现以上的例子将会是:
public class AnnotationSeason {
public static final int WINTER = 0;
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int FALL = 3;
public AnnotationSeason(@Season int season) {
System.out.println("Season :" + season);
}
@IntDef({WINTER, SPRING, SUMMER, FALL})
@Retention(RetentionPolicy.SOURCE)
public @interface Season {
}
public static void main(String[] args) {
AnnotationSeason annotationSeason = new AnnotationSeason(SPRING);
}
}
现在传入一些不同于Season的值时,编译器将会报错。
@StringDef
可以以同样的方式使用。
// Constants
public static final String WINTER = "Winter";
public static final String SPRING = "Spring";
public static final String SUMMER = "Summer";
public static final String FALL = "Fall";
// Declare the @ StringDef for these constants:
@ StringDef ({WINTER, SPRING, SUMMER, FALL})
@Retention(RetentionPolicy.SOURCE)
public @interface Season {}
下面是是Android性能关于Enum代价的视频(注意Youtube,如何查看请自行解决)
width="700" height="393" src="https://www.youtube.com/embed/Hzs6OBcvNQE" allowfullscreen="">
结论
Enums
比起使用普通常量会至增加2倍以上bytes到最终的APK大小,5到10倍更多的RAM。这个文章是一个关于性能优化最佳实践的应用。你可以参考学习更多关于support annotation library
。
- Support Library Features Guide | Android Developers
- Improve Code Inspection with Annotations | Android Studio