单例模式-下
Posted yuanjiehe
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式-下相关的知识,希望对你有一定的参考价值。
破坏单例模式的方法
序列化破坏
代码演示
// 内部类实现的单例模式
public class Singleton implements Serializable {
private Singleton() {
}
private static class SingletonHolder {
private static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
// 序列化
public class SingletonTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Singleton instance = Singleton.getInstance();
// 序列化
ObjectOutputStream oss = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oss.writeObject(instance);
// 反序列化
File file = new File("singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
Singleton newInstance = (Singleton)ois.readObject();
// 比较
System.out.println(instance);
System.out.println(newInstance);
}
运行结果
由运行结果不难发现两个对象实例不相同,违反了单例模式的初衷
解决方案
代码演示
// 修改后的单例模式
public class Singleton implements Serializable {
private Singleton() {
}
private static class SingletonHolder {
private static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
private Object readResolve() {
return SingletonHolder.instance;
}
}
运行结果
解决方案分析
由于Singleton实现了Serializable接口,使其可序列化,若未加readResolve函数便会利用反射方法开辟内存空间创建新的实例实现深拷贝,当加上readResolve方法时将会调用该方法实现浅拷贝从而避免出现多个实例。
参考博客:https://blog.csdn.net/u014653197/article/details/78114041
反射攻击
代码演示
// 内部类实现的单例模式
public class Singleton implements Serializable {
private Singleton() {
}
private static class SingletonHolder {
private static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
public class SingletonTest {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Singleton instance = Singleton.getInstance();
Class objectClass = Singleton.class;
// 获取构造器
Constructor constructor = objectClass.getDeclaredConstructor();
// 修改构造器权限
constructor.setAccessible(true);
// 利用构造器构造对象
Singleton newInstance = (Singleton) constructor.newInstance();
System.out.println(instance);
System.out.println(newInstance);
}
}
运行结果
解决方法
修改Singleton类的私有构造器,使其试图通过反射方法构造时将会抛出异常
private Singleton() {
if (SingletonHolder.instance != null) {
throw new RuntimeException("Singleton禁止反射调用");
}
}
另一种单例模式实现方法
实现代码
// 枚举类型实现的单例模式
public enum EnumSingleton {
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumSingleton getInstance() {
return INSTANCE;
}
}
优点
通过枚举类的特性使得JVM来帮我们保证线程安全和单例实例的问题
深入了解
通过Jad工具对EnumSingleton.class文件进行反编译得到如下代码
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: EnumSingleton.java
package com.reget.design.singleton;
public final class EnumSingleton extends Enum
{
public static EnumSingleton[] values()
{
return (EnumSingleton[])$VALUES.clone();
}
public static EnumSingleton valueOf(String name)
{
return (EnumSingleton)Enum.valueOf(com/reget/design/sigleton/EnumSingleton, name);
}
private EnumSingleton(String s, int i)
{
super(s, i);
}
public Object getData()
{
return data;
}
public void setData(Object data)
{
this.data = data;
}
public static EnumSingleton getInstance()
{
return INSTANCE;
}
public static final EnumSingleton INSTANCE;
private Object data;
private static final EnumSingleton $VALUES[];
static
{
INSTANCE = new EnumSingleton("INSTANCE", 0);
$VALUES = (new EnumSingleton[] {
INSTANCE
});
}
}
以上是关于单例模式-下的主要内容,如果未能解决你的问题,请参考以下文章