创建一个单例
Effective Java作者Josh Bloch 提倡使用枚举的方式。
枚举写法简单
public enum EasySingleton{ INSTANCE; } 你可以通过EasySingleton.INSTANCE来访问。
枚举自己处理序列化
我们知道,以前的所有的单例模式都有一个比较大的问题,就是一旦实现了Serializable接口之后,就不再是单例的了,因为,每次调用 readObject()方法返回的都是一个新创建出来的对象,有一种解决办法就是使用readResolve()方法来避免此事发生。但是, 为了保证枚举类型像Java规范中所说的那样,每一个枚举类型极其定义的枚举变量在JVM中都是唯一的,在枚举类型的序列化和反序列化上,Java做了特殊的规定。
在序列化的时候Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。同时,编译器是不允许任何对这种序列化机制的定制的,因此禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。
所以,JVM对序列化有保证。
枚举实例创建是thread-safe(线程安全的)
根据Java的ClassLoader机制,当一个Java类第一次被真正使用到的时候静态资源被初始化、Java类的加载和初始化过程都是线程安全的。所以,创建一个enum实例是线程安全的。
例如:
enum Type{
A,B,C,D;
}
创建上面的enum时,编译器会自动为我们生成一个继承自java.lang.Enum的类。
class Type extends Enum{
public static final Type A;
public static final Type B;
...
}
可以看到每个枚举实例都是static final类型的,也就表明只能被实例化一次。所以enum中的实例被保证只会被实例化一次,在我们访问枚举实例时会执行构造方法和初始化变量。
懒加载模式
public class SingletonDeSign {
public static void main(String[] args){
System.out.println("枚举类实现单例懒加载");
ConnectPool connectPool = ConnectPool.INSTANCE;
ConnectPool connectPool1 = ConnectPool.INSTANCE;
String connect = connectPool1.getConnect();
}
}
enum ConnectPool{
INSTANCE;
ConnectPool(){
System.out.println("执行ConnectPool的构造函数");
}
public String getConnect(){
return "connect";
}
}
类加载机制