本文共 1300 字,大约阅读时间需要 4 分钟。
定义枚举时使用 enum 和 class 一样, 是 Java 中的一个关键字。 就像 class 对应一个 Class 类一样, enum 也对应有一个 Enum 类。
通过将定义好的枚举反编译, 我们就能发现, 其实枚举在经过 javac 的编译之后, 会被转换成形如public final class T extends Enum
的定义。 而且, 枚举中的各个枚举项通过 static
来定义的。 如: public enum T { SPRING,SUMMER,AUTUMN,WINTER;}
反编译后代码为:
public final class T extends Enum { //省略部分内容 public static final T SPRING; public static final T SUMMER; public static final T AUTUMN; public static final T WINTER; private static final T ENUM$VALUES[];枚举类型和泛型 < 228 static { SPRING = new T("SPRING", 0); SUMMER = new T("SUMMER", 1); AUTUMN = new T("AUTUMN", 2); WINTER = new T("WINTER", 3); ENUM$VALUES = (new T[] { SPRING, SUMMER, AUTUMN, WINTER }); }}
1.枚举类型T不可被继承
2.T中所有属性都被static final
修饰,天然支持多线程,原因如下: 了解 JVM 的类加载机制的朋友应该对这部分比较清楚。 static 类型的属性会在类加载过程初始化, 当一个 Java 类第一次被真正使用到的时候静态资源被初始化、 Java 类的加载和初始化过程都是线程安全的( 因为虚拟机在加载枚举的类的时候, 会使用 ClassLoader 的 loadClass 方法, 而这个方法使用同步代码块保证了线程安全) 。
所以, 创建一个 enum 类型是线程安全的。
也就是说, 我们定义的一个枚举, 在第一次被真正用到的时候, 会被虚拟机加载并初始化, 而这个初始化过程是线程安全的。
而我们知道, 解决单例的并发问题, 主要解决的就是初始化过程中的线程安全问题。
所以, 由于枚举的以上特性, 枚举实现的单例是天生线程安全的。
同时,enum单例模式也支持序列化/反序列化:
在序列化的时候 Java 仅仅是将枚举对象的 name 属性输出到结果中,
反序列化的时候则是通过 java.lang.Enum
的 valueOf 方法
来根据名字查找枚举对象。
同时, 编译器是不允许任何对这种序列化机制的定制的, 因此禁用了 writeObject、 readObject、 readObjectNoData、 writeReplace 和 readResolve 等方法。
转载地址:http://xjkzi.baihongyu.com/