网站开发 APP开发 小程序开发 SEO优化 公司新闻

Java枚举类型原理

2018-05-18 10:14:28
1143

  枚举(Enum)类型是 java 5 中新增的一种数据类型,它能够帮助我们更加快捷和安全的实现枚举。

  回想之前我们在定义枚举常量时的做法:

  这样的定义方式虽然也能正常工作,但却存在许多不足,比如不小心把 MONDAY 和 TUESDAY 都置为 2 时,编译器并不会报错,但是却很难进行排查。

  在 Java 5 之后,我们可以用如下的定义定义枚举类型。并可以在程序中通过 的方式使用,这无疑大大提高了程序的安全性。

  我们知道,编程语言的设计具有前向兼容性,这意味着后续的语言特性实际上都是通过语法糖来实现的,那么枚举类型的内部实现原理是怎么样的呢?我们通过将上面的枚举类 Day 通过 命令进行反编译,再将反编译的代码通过改写使其更加容易阅读,最终得到下面的反编译代码。
 

  通过阅读上面的反编译后代码,我们可以对枚举类型的实现进行总结:

  枚举类型是通过继承 Enum 类来实现的,并且最终生成 final 类来强化不可变性。

  枚举类型的构造函数为私有的,具有 String 和 int 两个参数,分别代表枚举的名称和序号,序号按照定义的顺序从小到大排列。

  每一个枚举都代表一个枚举类事例,并且为 static 和 final,在枚举类的静态代码块中进行初始化,并且有一个 $VALUES 数组保存所有的枚举。

  通过 valueOf 方法可以完成枚举名称到枚举对象的查找。

  VALUES()方法返回的是 VALUES 数组被篡改。

  接下来,我们来分析一下自定义枚举类型所继承的 Enum 类

  通过阅读上面的 Enum 抽象类,我们可以对其特点进行总结:

  由 equals 方法可知每个枚举只与自身相等,没有等效相等的枚举。

  由 clone 方法可知枚举对象不允许克隆,这能保证每一个枚举都是唯一的。

  由 compareTo 方法可知枚举只能与同类型的枚举相比较,返回结果为枚举的顺序之差。

  由 finalize 方法可知枚举类不允许实现 finalize 方法,这与枚举的安全性有关。

  由 readObject 方法和 readObjectNoData 方法可知枚举对象不允许反序列化,这也能保证每一个枚举都是唯一的。

  由以上的分析我们可以发现,枚举的最大特点就是唯一性,同时可以发现只有单个元素的枚举在不经意间符合了单例模式的要求,具体为:

  枚举类为不可变类,这防止了单例类被继承。

  枚举类型的构造函数为私有的,因此不能主动创建对应的单例对象。

  枚举的元素为 public static final 类型,并且在类加载的时候在静态代码块内完成了初始化,这相当于单例模式的恶汉模式。

  枚举类对象不允许克隆,这能保证每一个单例都是唯一的。

  枚举类对象不可反序列化,这也能保证每一个单例都是唯一的。

  因此我们可以使用单元素的枚举类型来实现单例模式。事实上,正如Effective Java一书中所说的:单元素的枚举类型已经成为实现 Singleton 的最佳方法。

  注意:值得提出的时,由以上的分析我们知道每一个枚举都是一个对象,既然是对象,那么它所占的内存就比基本类型大很多,这就是枚举类型的缺点,所以在Android开发中并不建议使用枚举类型,而是使用等注解加上int或者String进行替代。