使用场景:
创建时间过长或者消耗内存资源过多时可使用单例模式
特点:
构造器私有化,提供唯一静态访问点
单例模式实现方法:
- 恶汉式
- 懒汉式
- 静态内部类
- 枚举(推荐)
- spring单例
public class HungrySingleton {
private static final HungrySingleton singleton = new HungrySingleton();
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return singleton;
}
}
public class DuobleCheckSingleton {
private static DuobleCheckSingleton singleton;
private DuobleCheckSingleton(){
}
private static DuobleCheckSingleton getInstance(){
if(singleton == null){
//类锁
synchronized (DuobleCheckSingleton.class){
if(singleton == null){
singleton = new DuobleCheckSingleton();
}
}
}
return singleton;
}
}
public class InnerClassSingleton {
private static InnerClassSingleton singleton;
private InnerClassSingleton(){
}
public static InnerClassSingleton getInstance() {
return getInnerClassSingleton.singleton;
}
private static class getInnerClassSingleton{
private static InnerClassSingleton singleton = new InnerClassSingleton();
}
}
破坏单例模式
- 反射破坏单例模式
- 反序列化破坏单例模式
反射破坏单例:
/**
* Constructor : 构造
* Accessible : 可使用的
*/
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
HungrySingleton singleton = HungrySingleton.getInstance();
HungrySingleton instance1 = (HungrySingleton)declaredConstructor.newInstance();
System.out.println(instance1);
反序列化破坏单例:
HungrySingleton s2 = HungrySingleton.getInstance();
fos = new FileOutputStream("HungrySingleton.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s2);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("HungrySingleton.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
s1 = (HungrySingleton)ois.readObject();
ois.close();
防止反射破坏&反序列化单例:
package com.singleton;
public class HungrySingleton {
private static final HungrySingleton singleton = new HungrySingleton();
private HungrySingleton(){
//防止反射破坏单例
if(singleton != null){
throw new RuntimeException("不允许创建多个对象");
}
}
public static HungrySingleton getInstance(){
return singleton;
}
//防止反序列化破坏单例
private Object readResolve(){
return singleton;
}
}
总结:
- 可反射获取单例类的私有构造器对象使用newInstance方法破坏对象
- 可通过ObjectInputStream的readObject破坏单例
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
return inst;
}
public final Object readObject()
//当类类型为枚举类时会抛出异常
Object obj = readObject0(false);
return obj;
}
故推荐枚举类实现单例。