单例(singleton)指仅仅只能被实例化一次的类,主要服务于一些需要保证对象只存在一个实例的场景。
实现方式一:暴露公有静态成员变量
public class Singleton {
public static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
}
INSTANCE
为对外暴露的成员变量,构造方法设为私有。
实现方式二:暴露公有静态方法
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
实例成员INSTANCE
与构造方法同时设为私有,通过静态成员方法getInstance()
对外暴露访问。上面这种写法称作若饿汉模式
,另外还有一种懒汉模式
的写法,INSTANCE
类加载时不初始化,在需要使用时才初始化。
public class Singleton {
private static Singleton INSTANCE = null;
private Singleton() {
}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
懒汉模式
存在线程安全问题,这里仅展示一下,不推荐使用。
实现方式三:包含单个元素的枚举类型
除了上面说到的两种方式,还有第三种实现单例的方法,即使用包含单个元素的枚举类型。
public enum Singleton {
INSTANCE;
}
枚举为什么可以实现单例?
通过对上面代码编译后的Singleton.class
反编译后得到下面的代码:
public final class Singleton extends Enum {
public static final Singleton INSTANCE;
private static final Singleton $VALUES[];
static {
INSTANCE = new Singleton("INSTANCE", 0);
$VALUES = (new Singleton[]{
INSTANCE
});
}
public static Singleton[] values() {
return (Singleton[]) $VALUES.clone();
}
public static Singleton valueOf(String name) {
return Enum.valueOf(Singleton.class, name);
}
private Singleton(String s, int i) {
super(s, i);
}
}
通过反编译后的代码我们可以看到,枚举实际上与我们写的普通类并无太大区别,只不过编译器帮我们简化了这部分工作。我们前面实现单例是将类的实例控制为一个,而枚举是类中定义了N个元素,则将类的实例控制为N个,所以当我们在枚举类中只定义一个元素时即可实现单例的效果。