背景
面试问到枚举是怎么保证单例的,刚好看了篇文章,总结一下。
实现
声明一个枚举 Season:
public enum Season {
SPRING, SUMMER, AUTUMN, WINTER;
}
经过编译后:
public abstract class Season { // 生成和枚举同名的抽象类
Season SPRING = new Season$1();
Season SUMMER = new Season$2();
Season AUTUMN = new Season$3();
Season WINTER = new Season$4();
final class Season$1 extends Season { // 真正的实现类
Season$1("SPRING", 0); // 调用 Enum类 的构造方法
}
// 其它内部类同理
Season[] $VALUES = new Season[4]; // values() 会用上
$VALUES[0] = SPRING;
$VALUES[1] = SUMMER;
$VALUES[2] = AUTUMN;
$VALUES[3] = WINTER;
public static Season[] values(){
return (Season[]) $VALUES.clone(); // 利用了 $VALUES
}
public static Season valueOf(String s){
return (Season) Enum.valueOf(Season.class, s); // Enum.valueOf 的本质是反射
}
}
枚举 经过编译后生成 同名抽象类,抽象类的 内部类 才是真正实现类。
如何保证单例
Enum#clone 用 final 修饰并禁止克隆,Enum#readObject 禁止反序列化复制枚举,从而保证了枚举变量是单例的。
参考文献