被破坏的单例模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dingjianmin/article/details/79948677
被破坏的单例模式


我们知道饿汉单例天生是线程安全的,但是通过其他途径单例模式是可以被破坏的。懒汉亦如此。


1、通过反射来破解单例模式

	public class Eagersingleton implements Serializable {

		private static final long serialVersionUID = 888L;
		private static Eagersingleton m_instance = new Eagersingleton();// 初始化时已经自行实例化

		// 私有默认构造方法
		private Eagersingleton() {
		}

		// 静态工厂方法
		public static Eagersingleton getInstance() {
			return m_instance;
		}
	}
	public class Test1 {

		public static void main(String[] args) throws NoSuchMethodException,
				SecurityException {
			// 获取单例对象
			Eagersingleton instance = Eagersingleton.getInstance();
			Eagersingleton instance2 = null;
			try {
				Class cls = Eagersingleton.class;
				Constructor constructor = cls.getDeclaredConstructor(null);
				// 关掉安全检查,可以调用私有构造器
				constructor.setAccessible(true);
				// 通过反射得到一个对象
				instance2 = (Eagersingleton) constructor.newInstance(null);
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(instance);
			System.out.println(instance2);
		}
	}
    
打印出来的结果不一样,说明这两个对象就是不同的对象,这样就破解了单例模式。

解决方案:避免反射


反射是通过它的Class对象来调用构造器创建出新的对象,我们只需要在构造器中手动抛出异常,导致程序停止就可以达到目的了。

2、通过序列化和反序列化破解单例

	public class Test2 {

		public static void main(String[] args) throws FileNotFoundException,
				ClassNotFoundException {
			// 获取单例对象
			Eagersingleton instance = Eagersingleton.getInstance();

			// 通过反序列化读取对象
			Eagersingleton instance2 = null;
			try {
				ObjectOutputStream oossStream = new ObjectOutputStream(
						new FileOutputStream("D:/EagersingletonTest.txt"));

				// 通过序列化把对象写到文件中
				oossStream.writeObject(instance);
				oossStream.flush();
				oossStream.close();
				// 读取文件的对象
				ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
						"D:/EagersingletonTest.txt"));

				instance2 = (Eagersingleton) ois.readObject();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			System.out.println(instance);
			System.out.println(instance2);
		}
	}

打印出来的结果不一样,说明这两个对象就是不同的对象,破解了单例模式。

解决方案:避免序列化

readResolve()这个方法是基于回调的,反序列化时,如果定义了readResolve()则直接返回此方法指定的对象,而不需要在创建新的对象。









每天努力一点,每天都在进步。

猜你喜欢

转载自blog.csdn.net/dingjianmin/article/details/79948677