总结先人的几种模式:
单例模式的几种总结:
一、饿汉式
二、懒汉是
三、双重检查锁实现单例模式
四、静态内部类实现单例模式
五、枚举式
/**
* 饿汉式
* @author Administrator
*
*/
public class EHS {
private EHS(){
}
//类初始化时,立即加载这个对象(没有延时加载的优势)。加载类时,天然的是线程安全的!
private static EHS ehs = new EHS();
public static EHS getEHS(){
return ehs;
}
}
/**
* 懒汉式
* @author Administrator
*
*/
public class LHS {
private LHS(){}
//类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)。
private static LHS lhs ;
//方法同步,调用效率低!
public static synchronized LHS getLHS(){
if(lhs==null){
lhs = new LHS();
}
return lhs;
}
}
/**
* 双重检查锁实现单例模式
*
*/
public class SingletonDemo3 {
private static SingletonDemo3 instance = null;
public static SingletonDemo3 getInstance() {
if (instance == null) {
SingletonDemo3 sc;
synchronized (SingletonDemo3.class) {
sc = instance;
if (sc == null) {
synchronized (SingletonDemo3.class) {
if(sc == null) {
sc = new SingletonDemo3();
}
}
instance = sc;
}
}
}
return instance;
}
private SingletonDemo3() {
}
}
/**
* 内部类式
* @author Administrator
*
*/
public class NBLS {
private NBLS(){}
private static class SingleClass{
private static final NBLS nbls = new NBLS();
}
//方法没有同步,调用效率高!
public static NBLS getNBLS(){
return SingleClass.nbls;
}
}
/**
* 枚举式实现单例模式(没有延时加载)
*
*/
public enum SingletonDemo5 {
//这个枚举元素,本身就是单例对象!
INSTANCE;
//添加自己需要的操作!
public void singletonOperation(){
}
}
破解单例模式,以懒汉式为例子:
第一种破解方法:
//通过反射的方式直接调用私有构造器
Class<LHS> clazz = (Class<LHS>) Class.forName("com.pattern.singleton.LHS");
Constructor<LHS> c = clazz.getDeclaredConstructor(null);
c.setAccessible(true);
LHS s3 = c.newInstance();
LHS s4 = c.newInstance();
System.out.println(s3);
System.out.println(s4);
防止反射方式通过私有构造器进行实例化:
private LHS(){ //私有化构造器
if(lhs!=null){
throw new RuntimeException();
}
}
在LHS类中,当通过反射方式用私有构造器进行获得实例时,直接抛出异常,让其只能调用get方法进行获取!
第二种破解方法:
//通过反序列化的方式构造多个对象
FileOutputStream fos = new FileOutputStream("f:/a.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s1);
oos.close();
fos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("f:/a.txt"));
LHS s5 = (LHS) ois.readObject();
System.out.println(s5);
防止破解方法:
//反序列化时,如果定义了readResolve()则直接返回此方法指定的对象。而不需要单独再创建新对象!(在LHS类中定义此方法,其实这是一种回调)
private Object readResolve() throws ObjectStreamException {
return lhs;
}