面试中常常问到单例模式,并且实际中也是经常使用的方式,但单例模式在哪些情况下会被破解呢?被破解了如何应对破解呢?
/**
* 饿汉式
*/
public class SingletonTest {
private SingletonTest(){
System.out.println("private SingletonTest()");
}
private static final SingletonTest INSTANCE = new SingletonTest();
public static SingletonTest getInstance(){
return INSTANCE;
}
public static void otherMethod(){
System.out.println("otherMethod()");
}
}这是一个单例模式,接下来用反射创建这个对象
public static void main(String[] args) throws Exception {
SingletonTest.otherMethod();
System.out.println(SingletonTest.getInstance());
reflection(SingletonTest.class);
}
private static void reflection(Class<?> clazz) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Constructor<?> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
System.out.println("反射创建实例:" + constructor.newInstance());
}返回结果
private SingletonTest()
otherMethod()
com.whf.mian.shi.single.SingletonTest@3c679bde
private SingletonTest()
反射创建实例:com.whf.mian.shi.single.SingletonTest@16b4a017如何应对这种情况呢?
在私有构造函数中增加一下代码,禁止通过反射机制调用
private SingletonTest(){
if(INSTANCE!=null){
throw new RuntimeException("单例对象不能重复创建");
}
System.out.println("private SingletonTest()");
}单例模式要实现序列化接口,才能够应用于序列化
/**
* 饿汉式
*/
public class SingletonTest implements Serializable {
private SingletonTest(){
System.out.println("private SingletonTest()");
}
private static final SingletonTest INSTANCE = new SingletonTest();
public static SingletonTest getInstance(){
return INSTANCE;
}
public static void otherMethod(){
System.out.println("otherMethod()");
}
}通过序列化创建这个对象
public static void main(String[] args) throws Exception {
SingletonTest.otherMethod();
System.out.println(SingletonTest.getInstance());
serializable(SingletonTest.getInstance());
}
private static void serializable(Object instance) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(instance);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
System.out.println("反序列化创建实例:"+ois.readObject());
}返回结果
private SingletonTest()
otherMethod()
com.whf.mian.shi.single.SingletonTest@3c679bde
反序列化创建实例:com.whf.mian.shi.single.SingletonTest@735f7ae5这种情况只需要在单例对象中添加readResolve方法,直接返回该对象即可
//防止反序列化对象
public Object readResolve(){
return INSTANCE;
}使用unsafe创建该对象
public static void main(String[] args) throws Exception {
SingletonTest.otherMethod();
System.out.println(SingletonTest.getInstance());
unsafe(SingletonTest.class);
}
private static void unsafe(Class<?> clazz) throws InstantiationException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
Constructor<?> constructor = Unsafe.class.getDeclaredConstructor();
constructor.setAccessible(true);
Unsafe o1 = (Unsafe) constructor.newInstance();
Object o = o1.allocateInstance(clazz);
System.out.println("Unsafe 创建实例:" + o);
}返回结果
private SingletonTest()
otherMethod()
com.whf.mian.shi.single.SingletonTest@3c679bde
Unsafe 创建实例:com.whf.mian.shi.single.SingletonTest@16b4a017这种方式还不知道怎么预防。
| 留言与评论(共有 0 条评论) “” |