枚举确实比简单的静态变量占用的内存要更多。
Android 简单替代枚举的方法
严格来讲,这个使用方法是有很多缺陷的,但是使用下面的方法就能满足需求的话,那么用Java Enum
是会带来各种更大的开销。
- 方法一:使用接口变量
接口变量默认都是public static final
的,个人理解接口只是对一类事物的属性和行为更高层次的抽象。对修改关闭,对扩展(不同的实现implements
)开放,接口是对开闭原则的一种体现。
public interface ErrorCode {
int ERROR_MANUAL_EXP = 100;
int ERROR_MANUAL_BACK = 101;
}
使用javap Color.class
反编译class
文件,查看生成的字节码,如下:
Compiled from "ErrorCode.java"
interface org.fast.clean.ErrorCode {
public static final int ERROR_MANUAL_EXP;
public static final int ERROR_MANUAL_BACK;
}
可以看出就是一个public static final
的静态变量。
- 方法二:使用support-annotations 注解库
从Android Support Library19.1
版本开始引入了一个新的注解库,使用 com.android.support:support-annotations
,这个官方的注解支持库中包含了许多很好的注解,可以帮助我们在编译的时候就找到错误。IntDef
和 StringDef
是包含在库中的两个关于常量的注解,我们可以用来代替枚举其中包括了很多有用的元注解,可以用来修饰代码,如@NonNull
,@StringRes
,@IntDef
,@StringDef
等等
下面我们使用@IntDef
来替代枚举,方法如下
public static final int RED = 0;
public static final int BLUE = 1;
public static final int GREEN = 2;
@IntDef({RED, BLUE, GREEN})
@Retention(RetentionPolicy.SOURCE)
public @interface Colors {
}
gradle 依赖:
dependencies { compile ‘com.android.support:support-annotations:24.2.0’ }
等等还有其他方法。
枚举单例
枚举在单例的使用也是很平常的
public enum SingleTon {
INSTANCE;
}
//单例对象的获取:
SingleTon instance = SingleTon.INSTANCE;
通过查看java.lang.Enum
源码如下:
/**
* prevent default deserialization
*/
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
throw new InvalidObjectException("can't deserialize enum");
}
private void readObjectNoData() throws ObjectStreamException {
throw new InvalidObjectException("can't deserialize enum");
}
对于单例是否安全,主要考虑以下两方面:序列化和反序列方面、线程安全方面。
- 对于序列化和反序列化,因为每一个枚举类型和枚举变量在JVM中都是唯一的,即Java在序列化和反序列化枚举时做了特殊的规定,枚举的
writeObject
、readObject
、readObjectNoData
、writeReplace
和readResolve
等方法是被编译器禁用的,因此也不存在实现序列化接口后调用readObject
会破坏单例的问题。 - 对于线程安全方面,类似于普通的饿汉模式,通过在第一次调用时的静态初始化创建的对象是线程安全的。
所以使用枚举也是一种比较好的单例模式,通过反编译我们知道,缺点就是不能够继承,因为final
了。
通过上面的分析枚举,我们只是讨论为什么说枚举更占内存,枚举原理是什么,而不是让我们拒绝使用枚举,因为就几个枚举,让应用内存开销大,那就实在是太可怕了。。。更重要的是通过比较字节码和源代码,我们可以发现很多的问题,一个很重要的作用就是了解很多编译器内部的工作机制。