您的位置:首页 > 移动开发 > Android开发

Android是否推荐使用枚举(enum)?使用枚举的利弊以及枚举倒底占多少内存?

2018-03-09 13:11 393 查看
一、安卓中是否推荐使用枚举enum
产生: 
enum的全称为 enumeration,是 JDK1.5 中引入的新特性,存放在 java.lang 包中,包括Enum,EnumSet,EnumMap等。 
其中Enum就是我们在C或C++中见过的枚举类型,但是Java中的枚举又比C或C++中的枚举更成熟和复杂。
Android官方建议: 


 
Android官网不建议使用enums,占用内存多(Enums often require more than twice as much memory as static constants.)。 
Enum 需要占用较大的内存,如果对内存敏感,请尽量少使用 Enum,换用做静态常量。
二、利弊和占用内存
在Java1.5以前,我们要定义常量的话一般都是使用类常量或者接口常量,接口常量可能用的更少一些。 
比如我们要定义4个颜色的常量。用类常量和枚举分别定义的话,就如下的实现方式:
//静态常量类
public class Color{
public static final int COLOR_RED = 1;
public static final int COLOR_GREEN = 2;
public static final int COLOR_YELLOW = 3;
public static final int COLOR_Blue = 4;
}
//枚举常量类
public enum ColorEnum {
RED, GREEN, YELLOW, BLUE;
}
上面的代码中,我们分别定义了类常量和枚举常量。从定义上看,枚举常量显然更简单,让代码看起来更简洁,只要定义各个枚举项,而不需要定义值等。
安卓官方建议:Enums often require more than twice as much memory as static constants.
枚举一般需要比静态常量超过两倍多的内存。
关于具体要占用多少内存呢?说得比较模糊。
内存占用对比举例说明:
public enum MonthEnum {
// 4 bytes
JANUARY,  // -> 87 bytes
// 4 bytes
FEBRUARY  // ->  88 bytes

// 生成的数组 24 + 4 + 4
// MonthEnum[] values
}

public class MonthConst {
// 4 bytes
public static final int JANUARY = 1;
// 4 bytes
public static final int FEBRUARY = 2;
}

public class UseMonth {
// 4 bytes
private int mMonth = MonthConst.JANUARY;
// 4 bytes
private MonthEnum mMonthEnum = MonthEnum.JANUARY;
}
我们不考虑 MonthEnum 和 MonthConst 他们对于 dex 大小的影响,这个没什么意义,几十个 Enum 占用的大小,也不及一张图片。
我们要对比的是 UseMonth 中这两种写法所占用的内存大小在 Dalvik 虚拟机下的区别。
在 UseMonth 中,他们一个是 int 类型,一个是对象引用,都是 4 字节,没有区别。
我们对比的大小,指的是对象本身的大小加上对象成员指向的其他对象大小,即 shadow heap + maintain heap。
 1.MonthEnum
  对于一个 MonthEnum, JANUARY 和 FEBRUARY 是两个指向 MonthEnum 实例的引用。他们分别占用 4 个字节。
  他们指向的实例对象还要占用额外的内存。
  我们看看 enum 的定义:
class Enum {
private final String name;
private final int ordinal;
}
  作为 Enum 成员变量 name(对象引用) 和 ordinal(int) 他们各占用 4 个字节,该对象实例占用: 
  12 + 4 + 4 = 20bytes,对齐之后是 24 字节。 
An empty object will take 16bytes, 12 bytes for overhead, 4 bytes for padding. 
参考:https://www.liaohuqiu.net/posts/android-object-size-dalvik/
  但是,name 是字符串,空字符串对象本身就是 32 字节,加上其中的字符数组最少也会占据 24 个字节, 
   对字符串加字符数组最少会占据 56 个字节。故一个 Enum 实例,最少 80 个字节。
  MonthEnum.JANUARY,含有 7 个字符,87 个字节;MonthEnum.FEBRUARY,8 个字符,88 个字节。
  枚举编译完之后 会有一个 values() 数组,两个对象引用的数组占用: 24 + 4 + 4 = 32 bytes。
  总计是: 4 + 4 + 87 + 88 + 32
 2.MonthConst
  JANUARY 和 FEBRUARY 各占 4 个字节。共计 8 个字节。
  总计是: 4 + 4
上面我们对比了只具有两个枚举值的枚举和常量,如果数量更多的话,枚举的命名更长的话,这个差距会更大。
文档所说的两倍
所以实际占用的内存,并非文档所说的两倍左右。
假设有 n 个枚举值,仅仅考虑枚举类,静态占用的内存,n 个引用 + n 个数组 + 24 空数组长度: 8n + 24。
而对于 n 个值的常量,则有 4n 字节。当 n 很大时,这样的关系是两倍,但是枚举引用所指向的内存(retained heap)没有考虑进来。
该用不该用?
官方文档提到:You should strictly avoid using enums on Android.
枚举有其其他它的特性,如果你需要这些特性,比如:非连续数值的判断,重载等时,可以用。
另外,内存用量也并非那么地可怕,枚举带来的编码的便捷,代码可读性的提升也是很大的利好。
看到这里,你应该了解了所有的细节了,是否该用,各位自己权衡。
如何更好地使用常量
如果应用确实对内存用量敏感,或者你就是追求极致,可用常量来代替枚举。
常量一般会和 Bit Mask 结合起来用,这样可以极致地减少了内存使用,同时使代码有较好的可读性。
参考:https://www.liaohuqiu.net/cn/posts/android-enum-memory-usage/
版权声明:本文为博主原创文章,未经博主允许不得转载。 http://blog.csdn.net/xmc281141947/article/details/56486970
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐