Effective Java—03 使用私有构造方法或枚类实现 Singleton 属性
Singleton
Singleton是指仅仅被实例化过一次的类。它通常被用来表示本质上唯一的系统的组件,例如,窗口组件或文件系统。
使用场景
想控制实例数目,节省系统资源的时候。例如web中的计数器,不用每次刷新都在数据库里加一次,用单例模式实现且缓存起来。
实现方式
有两种常见的方法来实现单例。两者都基于保持构造方法私有和提供公共静态成员以提供对唯一实例的访问。
保持构造方法私有
构造方法私有化后外部就无法通过new来创建对象(可以在外部通过反射调用私有构造器创建),我们可以在类加载时创建一个对象并缓存起来(static final)。
- 构造方法私有化+公有静态类的实例
public class Singleton {
/** 1. 构造方法私有化+公有静态对象实例*/
private Singleton(){}
public static final Singleton single = new Singleton();
public void doSomething(){}
}
public class SingletonTest {
public static void main(String[] args) {
Singleton singleton1 = Singleton.single;
Singleton singleton2 = Singleton.single;
System.out.println(singleton1 == singleton2);
}
}
- 构造方法私有化+私有静态类的实例+公共静态方法
public class Singleton {
/** 2. 构造方法私有化+私有静态类的实例+公共静态方法*/
private Singleton(){}
private static final Singleton single = new Singleton(); //也可以通过静态内部类加载一个实例
public static Singleton newInstance(){
return single; //多线程下有安全问题,应该使用懒汉式的double check
}
public void doSomething(){}
}
public class SingletonTest {
public static void main(String[] args) {
Singleton singleton1 = Singleton.newInstance();
Singleton singleton2 = Singleton.newInstance();
System.out.println(singleton1 == singleton2);
}
}
声明单一枚举类型
public enum EnumSingleton {
INSTANCE;
public EnumSingleton getInstance(){
return INSTANCE;
}
}
完整的枚举单例:
public class User {
//私有化构造函数
private User(){ }
//定义一个静态枚举类
static enum SingletonEnum{
//创建一个枚举对象,该对象天生为单例
INSTANCE;
private User user;
//私有化枚举的构造函数
private SingletonEnum(){
user=new User();
}
public User getInstnce(){
return user;
}
}
//对外暴露一个获取User对象的静态方法
public static User getInstance(){
return SingletonEnum.INSTANCE.getInstnce();
}
}
这种方式类似于公共属性方法,但更简洁,无偿地提供了序列化机制,并提供了防止多个实例化的坚固保证,即使是在复杂的序列化或反射攻击的情况下。这种方法可能感觉有点不自然,但是 单一元素枚举类通常是实现单例的最佳方式。注意,如果单例必须继承 Enum
以外的父类 (尽管可以声明一个 Enum
来实现接口),那么就不能使用这种方法。
参考文章:
- https://www.jianshu.com/p/4f56c3735464
- https://www.cnblogs.com/cnndevelop/p/12739276.html
- https://github.com/wangdecheng/effective-java-3rd-chinese/projects