java 单例模式 反射破解单例模式(不包含枚举式)实现方式

 

package singleton;
/**
*@author Danbro
*@version 创建时间:2019年6月26日下午3:42:51
*@funcition 懒汉式单例模式
**/
public class SingTonDemo06 {
	private static SingTonDemo06 instance;
	
	private SingTonDemo06() {
	}
	
	public static synchronized SingTonDemo06 getInstance() {
		if (instance == null) {
			instance = new SingTonDemo06();
		}
		return instance;
	}

}

运行

package singleton;

import java.lang.reflect.Constructor;

/**
*@author Danbro
*@version 创建时间:2019年6月26日下午4:33:30
*@funcition 
**/
public class Client02 {
	public static void main(String[] args) throws Exception {
		SingTonDemo06 s1 = SingTonDemo06.getInstance();
		SingTonDemo06 s2 = SingTonDemo06.getInstance();
		System.out.println(s1);
		System.out.println(s2);
		
		//运用反射 
		Class<SingTonDemo06> claz = (Class<SingTonDemo06>) Class.forName("singleton.SingTonDemo06");
		//通过反射获得原本私有的无参构造器
		Constructor<SingTonDemo06> c = claz.getDeclaredConstructor(null);
		//关闭安全检查
		c.setAccessible(true);
		//通过构造器实例化对象
		SingTonDemo06 s3 = c.newInstance();
		SingTonDemo06 s4 = c.newInstance();
		System.out.println(s3);
		System.out.println(s4);
		
	}
}
singleton.SingTonDemo06@15db9742
singleton.SingTonDemo06@15db9742
singleton.SingTonDemo06@6d06d69c
singleton.SingTonDemo06@7852e922

会发现 通过反射可以破解单例模式

这样修改SingTonDemo06代码

package singleton;
/**
*@author Danbro
*@version 创建时间:2019年6月26日下午3:42:51
*@funcition 懒汉式单例模式
**/
public class SingTonDemo06 {
	private static SingTonDemo06 instance;
	
	private SingTonDemo06() {
		//如果对象不为空 则抛出异常
		if (instance != null) {
			throw new RuntimeException();
		}
	}
	
	public static synchronized SingTonDemo06 getInstance() {
		if (instance == null) {
			instance = new SingTonDemo06();
		}
		return instance;
	}

}

通过反序列化的方式构造多个对象

package singleton;
/**
*@author Danbro
*@version 创建时间:2019年6月26日下午3:42:51
*@funcition 懒汉式单例模式
**/

import java.io.Serializable;


public class SingTonDemo07 implements Serializable{
	private static SingTonDemo07 instance;
	
	private SingTonDemo07() {
		//如果对象不为空 则抛出异常
		if (instance != null) {
			throw new RuntimeException();
		}
	}
	
	public static synchronized SingTonDemo07 getInstance() {
		if (instance == null) {
			instance = new SingTonDemo07();
		}
		return instance;
	}

}
package singleton;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;

/**
*@author Danbro
*@version 创建时间:2019年6月26日下午4:33:30
*@funcition 通过反序列化的方式构造多个对象
**/
public class Client03 {
	public static void main(String[] args) throws Exception {
		SingTonDemo07 s1 = SingTonDemo07.getInstance();
		SingTonDemo07 s2 = SingTonDemo07.getInstance();
		System.out.println(s1);
		System.out.println(s2);
		
		//序列化  把对象存到硬盘上
		FileOutputStream fos = new FileOutputStream("D:/a.txt");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(s2);
		fos.close();
		oos.close();
		//反序列化  从硬盘上读取对象
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/a.txt"));
		SingTonDemo07 s3 = (SingTonDemo07) ois.readObject();
		System.out.println(s3);
		
		
	}
}
singleton.SingTonDemo07@15db9742
singleton.SingTonDemo07@15db9742
singleton.SingTonDemo07@776ec8df

会发现 序列化前的对象和序列化后的对象不是同一个对象,破解了单例

解决办法

定义一个readResolve方法

   在反序列化时会调用此方法而不需要再反序列化另一个对象

package singleton;
/**
*@author Danbro
*@version 创建时间:2019年6月26日下午3:42:51
*@funcition 懒汉式单例模式
**/

import java.io.Serializable;


public class SingTonDemo07 implements Serializable{
	private static SingTonDemo07 instance;
	
	private SingTonDemo07() {
		//如果对象不为空 则抛出异常
		if (instance != null) {
			throw new RuntimeException();
		}
	}
	
	public static synchronized SingTonDemo07 getInstance() {
		if (instance == null) {
			instance = new SingTonDemo07();
		}
		return instance;
	}
	
	//在反序列化时会调用此方法而不需要再反序列化另一个对象
	private Object readResolve(){
		return instance;
	}
}
singleton.SingTonDemo07@15db9742
singleton.SingTonDemo07@15db9742
singleton.SingTonDemo07@15db9742

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值