单例模式( Singleton)
- 单例模式确保某一个类只有一个实例,而且自行实例化向整个系统提供这个实例。
- 单例模式三要素
1)某个类只能有一个实例
2)必须自行创建这个实例
3)必须像整个系统提供这个实例
- 饿汉式单例类(类加载时就实例化)
在类被加载时,静态变量会被初始化,此时类的私有构造子会被调用。因为构造方法是私有的,所以外界无法实例这个类,也无法继承。
/**
1. 饿汉式单例类
2. @date 2020/7/27 15:50
*/
public class EagerSingleton {
private static final EagerSingleton es = new EagerSingleton();
/**
* 私有的构造方法
*/
private EagerSingleton() {
}
/**
* 静态工厂方法
* @return
*/
public static EagerSingleton getInstance(){
return es;
}
}
- 懒汉式单例类
特点:构造方法私有,只有在单例类第一次被引用时才将自己实例化。
/**
1. 懒汉式单例类
2. @date 2020/7/27 15:54
*/
public class LazySingleton {
private static LazySingleton ls = null;
/**
* 私有构造方法,保证外界直接无法实例化
*/
private LazySingleton() {
}
/**
* 静态工厂方法
* @return
*/
synchronized public static LazySingleton getInstance(){
if(ls==null){
ls = new LazySingleton();
}
return ls;
}
注意:懒汉式单例类在实例化时,必须处理好在多个线程同时首次引用此类时的访问限制问题,特别是单例类作为资源控制器在实例化时必然涉及资源初始化,而资源初始化耗费时间长,这就意味着多个线程同时首次引用此类的几率变大。
- 登记式单例类
/**
1. 登记式单例类
2. @date 2020/7/27 15:59
*/
public class RegSingleton {
static private HashMap registry = new HashMap();
static {
RegSingleton regSingleton = new RegSingleton();
registry.put(regSingleton.getClass(),regSingleton);
}
/**
* 受保护的构造方法
*/
protected RegSingleton(){}
/**
* 静态工厂方法
*/
static public RegSingleton getInstance(String name){
if(name==null){
name = "com.singleton.RegSingleton";
}
if(registry.get(name)==null){
try {
registry.put(name,Class.forName(name).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
return (RegSingleton) registry.get(name);
}
}
登记式单例类是可以继承的。但是由于子类必须允许父类以构造方法调用产生实例,因此它的构造方法必须是公开的,这样的话就等于允许了以这样方法产生实例而不再父类的登记中,这是登记式单例类的一个缺点。缺点二:必须有父类的实例才能有子类的实例。
- 单例模式使用条件
系统中要求一个类只有一个实例时才应当使用单例模式