内容参考23种设计模式
单例模式定义
指一个类 只有一个实例,且该类能 自行创建 这个实例的一种模式。
单例模式特点
根据上面的定义可知单例模式有 3 个特点:
- 单例类只有一个实例对象;
- 该单例对象必须由单例类自行创建;
- 单例类对外提供一个访问该单例的全局访问点。
单例模式的主要角色:
- 单例类:包含一个实例且能自行创建这个实例的类。
- 访问类:使用单例的类。
思考:
1. 单例模式如何保证不被外部类实例化?
要保证单例类不被外部类实例化,那就必须重载构造方法,并且要设置为private 访问权限。
2. 外部类如何获取单例模式的类实例?
外部类不能new出单例模式的类,所以需要提供一个非 private 的方法供外部类调用(也可以通过反射获取,见下方代码),而且外部类调用时还没有获取到类的实例,所以该方法需要通过类名调用,所以该方法必须是static的。
3. 单例模式何时实例化?
这个问题就衍生出了单例模式的两种方式:
饿汉模式:
静态变量初始化时new出来实例,一旦类被加载就会生成实例:
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){
}
public static Singleton getSingleton(){
return singleton;
}
public void sayHello(){
System.out.println("hello");
}
}
懒汉模式:
外部类调用 获取实例 的方法时再生成实例:(要注意线程安全问题)
public class Singleton {
private static volatile Singleton singleton = null;
private Singleton(){
}
public static synchronized Singleton getSingleton(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
public void sayHello(){
System.out.println("hello");
}
}
通过反射获取private修饰的构造方法生成实例:
这种方式只是突然想到的获取实例的一种方式,不需要提供给外部类获取实例的方法。首先,这种方式不满足定义中的“自行创建实例”的条件;其次,通过反射可以获取多个实例。所以这种方式并不是单例模式的实现形式。
/**
* 一个单例模式的类
*/
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){
}
public void sayHello(){
System.out.println("hello");
}
}
public class Main {
public static void main(String[] args) {
Class clazz = Singleton.class;
Constructor cons = null;
try {
//获取无参构造函数
cons = clazz.getDeclaredConstructor(null);
//设置私有方法可访问
cons.setAccessible(true);
//获取实例
Singleton singleton = (Singleton) cons.newInstance(null);
singleton.sayHello();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}