背景
面試問到枚舉是怎麼保證單例的,剛好看了篇文章,總結一下。
實作
聲明一個枚舉 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 禁止反序列化複制枚舉,進而保證了枚舉變量是單例的。
參考文獻