Android 开发中是否应该使用枚举?
<blockquote><p>本文由咕咚发布在个人博客,转载请注明出处。</p>
<p>本文永久地址:https://gudong.name/2019/11/04/use-enum-or-not.html</p>
</blockquote>
<hr>
<p>在 Android 官方文档推出性能优化的时候,从一开始有这样一段说明:</p>
<blockquote>
<p>Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.</p>
</blockquote>
<p>意思是说在 Android 平台上 <strong>avoid</strong> 使用枚举,因为枚举类比一般的静态常量多占用两倍的空间。</p>
<blockquote>
<p>如果你还不了解枚举,参看文章 枚举介绍以及枚举的本质。</p>
</blockquote>
<p>由于枚举最终的实现原理还是类,在编译完成后,最终为每一种类型生成一个静态对象,而在内存申请方面,对象需要的内存空间远大于普通的静态常量,而且分析枚举对象的成员变量可知,每一个对象中默认都会有一个字符数组空间的申请,计算下来,枚举需要的空间远大于普通的静态变量。具体分析可见这篇文章。</p>
<p>所以,照此来看,在 Android 这样对内存寸土必争的平台上,如果只是使用枚举来标记类型,那使用静态常量确实更优,但是现在翻看官方文档发现,这个建议已经被删除了。(</p>
<p>为什么官方会删除?难道是之前的建议有错误吗,或者描述的不够精确?</p>
<p>个人认为,枚举占用空间比普通类型的静态常量大,这是事实,没问题,但是据此就建议不在 Android 中使用时不妥的,具体看 JakeWharton 在 reddit 上的一个评论。</p>
<blockquote>
<p>The fact that enums are full classes often gets overlooked. They can implement interfaces. They can have methods in the enum class and/or in each constant. And in the cases where you aren't doing that, ProGuard turns them back into ints anyway.</p>
<p>The advice was wrong for application developers then. It's remains wrong now.</p>
</blockquote>
<p>最重要的一句是</p>
<blockquote>
<p>ProGuard turns them back into ints anyway.</p>
</blockquote>
<p><strong>在开启 ProGuard 优化的情况下,枚举会被转为 int 类型</strong>,所以内存占用问题是可以忽略的。具体可参看 ProGuard 的优化列表页面 Optimizations Page,其中就列举了 enum 被优化的项,如下所示:</p>
<blockquote>
<p>class/unboxing/enum</p>
<p>Simplifies enum types to integer constants, whenever possible.</p>
</blockquote>
<p>既然 ProGuard 会把枚举优化为整形,那是不是在 Android 中,就可以继续无所顾忌的使用枚举了呢?😊</p>
<p><strong>并不是!!!</strong></p>
<p>ProGuard 对枚举的优化有一定的限制条件,如果枚举类存在如下的情况,将不会有优化为整形,如下所示:</p>
<ol>
<li>枚举实现了自定义接口。并且被调用。</li>
<li>代码中使用了不同签名来存储枚举。</li>
<li>使用 instanceof 指令判断。</li>
<li>在枚举加锁操作。</li>
<li>对枚举强转。</li>
<li>在代码中调用静态方法 valueOf 方法。</li>
<li>定义可以外部访问的方法。</li>
</ol>
<blockquote>
<p>参考自:ProGuard 初探 · dim's blog,另外,上面的这七种情况,我并没有找到官方的说明,如果有哪位读者知道,请在评论区里留下链接,谢谢啦~</p>
</blockquote>
<p>也就是说,要保证枚举能被正常优化为整形,就要确保枚举足够简单,如下所示,这些情况下的枚举都是可以被优化的</p>
<pre><code class="language-java">enum Color{
Red,Black,Green
}
</code></pre>
<p>或者这样的</p>
<pre><code class="language-java">enum Date {
Sunday("星期日"),
Monday("星期一"),
Tuesday("星期二"),
Wednesday("星期三"),
Thursday("星期四"),
Friday("星期五"),
Saturday("星期六");
public String value;
private Date(String value) {
this.value = value;
}
}
</code></pre>
<p>但是再次查看那七条规则,会发现这几个规则几乎把枚举面向对象的特性都限制了,在这样的限制下,枚举好用的地方都将消失,失去了枚举的灵活性。</p>
<p>到这里就有点矛盾了,枚举很好用,ProGuard 也会对它进行优化,但是优化条件限制了我们更好的使用枚举,那我们应该怎么面对这种情况,我的几点建议:</p>
<ul>
<li>对于简单的使用场景,比如 Color、Week 这种,枚举有更好的语义性,可以优先使用枚举。</li>
<li>一些时候使用枚举可能无法避免上面七种情况的,权衡易用性和性能以及使用场景,可以考虑继续使用枚举,因为枚举在有些时候确实让代码更简洁,更容易维护,牺牲点内存也无妨。</li>
</ul>
<hr>
<p>至于 Android 为什么会把那条优化建议删掉,我认为官方也是考虑到了枚举会被优化为整形这一点,所以才去掉的。</p>
<p>然后实际工作中具体怎么使用,官方就不在说<strong>”avoid“</strong> 了,而是让开发者自行决定是不是使用枚举。</p>
<p>以上就是关于 这个问题我的一些思考。</p>
<h2 id="关于作者">关于作者</h2>
<p>咕咚,Android 工程师,个人博客 gudong.name,公众号:咕喱咕咚</p>
<p><img src="https://ws3.sinaimg.cn/large/006tNbRwgy1fykl72khq0j305g05g0sq.jpg"></p>
<h2 id="参考链接">参考链接</h2>
<ul>
<li>Android 中的 Enum 到底占多少内存?该如何用? | Yet Another Summer Rain</li>
<li>关于Java中枚举Enum的深入剖析 - 技术小黑屋</li>
<li>should-i-strictly-avoid-using-enums-on-android</li>
<li>"You should strictly avoid using enums on Android" : androiddev</li>
<li>ProGuard 初探 · dim's blog</li>
</ul><br><br>
来源:https://www.cnblogs.com/mgudong/p/11842947.html
頁:
[1]