Enum在Java语言中代表一个数据类型,它包含了一组固定不变的恒量。当我们的需求中需要预先定义一组常量来代表一个数据的时候,那么我们就使用Enum。当一个变量可以被赋予一组相关信息的数据的时候,我们就可以使用枚举了,例如:
使用枚举来代替Integer或者String类型的数据可以提升编译阶段的检查时间以及避免一些数据类型不合法造成的编译错误。
枚举带来的坏处
Enum中的每个值都是作为一个对象存在的,并且每次使用的时候都会占用一些内存来引用这些对象。故相比较于Integer或者String类型的常量,它更占用内存。即使在低版本的设备上(<=2.2)JIT编译器针对枚举做了优化工作,也是比不上使用Integer和String的常量的占用的内存少。
在项目中使用一个单独的枚举将要增加最终编译后的dex文件的大小,不仅如此它还会产生运行时的系统开销而且应用需要更大的存储空间。
所以过度使用Enum将会导致Apk包的扩增以及运行时内存消耗
如果你的应用正在过度使用枚举的话,赶紧将他们替换为Integer或者String的常量吧!但是这样还是会有问题….
解决方案
Android中提供了注解库,该库中有一个TypeDef
的注解。该注解可以应用在参数、返回类型以及成员变量上来指定一组特别的常量。他们还支持编译自动分配常量。
IntDef
和StringDef
是两个魔法常量注解,也可以用来替代Enum的使用。该注解可以在编译阶段帮助我们检查变量的复制分配。
如何使用
下面看一个简单的例子来理解如何使用:ConstantSeason类
很不幸,使用该方法时用户不能保证在构造器中传入合适的参数,所以该方法类型不安全的做法。
同样使用枚举来实现:
现在,我们来看看如何使用注解的魔法常量。
首先在Gradle文件中添加support-annotations库的依赖
dependencies { compile ‘com.android.support:support-annotations:24.2.0’ }
声明@IntDef
的常量
|
|
这里的Typedef
注解使用了@interface
来声明了新的枚举注解类型。使用@Retention
来声明枚举类的声明周期,使用@IntDef
来声明枚举元素。RetentionPolicy.SOURCE
则告诉编译器不要把枚举编译到字节码文件中。
所以,具体实现代码如下:
|
|
现在,如果我们向构造器中传递一个非season值的话,编译器将直接报错。
同理,@StringDef
也可以按照上述方法声明。
|
|
总结
通过以上分析我们知道:相比较使用普通常量和RAM内存可以使用5到10倍等效常数,而使用枚举将至少添加两倍的字节总数从而增大APK尺寸。
使用普通Integer和String常量也是最佳实践建议和性能优化方法。