《Effective Java》一书中提到,单元素的枚举类型,功能完整、使用简洁、无偿提供了序列化机制,在面对复杂的序列化或者反射攻击时仍然可以绝对防止多次实例化等优点,被作者认为是实现单例模式的最佳方法(也是一种饿汉式)。
实现非常简单:
public enum Singleton {
INSTANCE;
public void getOtherMethod() {
}
}
调用也非常简单:
Singleton.INSTANCE.getOtherMethod();
那么,枚举是如何保证线程安全的呢?首先我们来看一个简单的枚举类。
public enum DemoEnum {
FIRST,SECOND,THIRD,FOURTH
}
然后将它反编译,看看这段代码是如何实现的
public final class DemoEnum extends Enum {
private DemoEnum(String s, int i) {
super(s, i);
}
public static DemoEnum[] values() {
DemoEnum at[];
int i;
DemoEnum at1[];
System.arraycopy(at = ENUM$VALUES, 0, at1 = new T[i = at.length], 0, i);
return at1;
}
public static DemoEnum valueOf(String s) {
return (DemoEnum)Enum.valueOf(demo/DemoEnum, s);
}
public static final DemoEnum FIRST;
public static final DemoEnum SECOND;
public static final DemoEnum THIRD;
public static final DemoEnum FOURTH;
private static final DemoEnum ENUM$VALUES[];
static {
SPRING = new T("FIRST", 0);
SUMMER = new T("SECOND", 1);
AUTUMN = new T("THIRD", 2);
WINTER = new T("FOURTH", 3);
ENUM$VALUES = (new T[] {
FIRST, SECOND, THIRD, FOURTH
});
}
}
我们可以看到,这个类是final的,不可被继承,并且继承了Enum。并且这个类中的属性和方法都是static的,在类被加载之后初始化。虚拟机在加载类的时候,使用了ClassLoader的loadClass方法,这个方法使用了同步代码块保证了线程安全。
序列化对单例的破坏(非枚举)
序列化会通过反射调用无参数的构造方法创建一个新的对象
下面我们来具体解释一下,
写个测试类:
public class Singleton implements Serializable{
private final static Singleton INSTANCE = new Singleton();
private Singleton(){};
public static Singleton getInstance(){return INSTANCE;}
public static void main(String[] args)