想要破坏单例模式,可以在定义的单例类Singleton创建多个对象.枚举方式除外,还有两种方式,序列化和反射.我们先看序列化.不知道序列化的可以点击以下链接进行学习,博主讲了很详细.http://t.csdn.cn/2oNXN
单例模式代码:
import java.io.Serializable; public class Singleton implements Serializable { //私有构造方法 private Singleton(){ } //定义一个静态内部类 private static class SingletonHolder{ //在内部类中声明并初始化外部类的对象 private static final Singleton INSTANCE = new Singleton(); } //提供公共的访问方式 public static Singleton getInstance(){ return SingletonHolder.INSTANCE; } }
测试类,序列化破坏单例模式
代码演示:
public class Client { public static void main(String[] args) throws Exception{ writeObject2File();//注意此处,先注释下面两个readObjectFromFile()方法,然后在运行 readObjectFromFile();//writeObject2File(),运行完后在注释writeObject2File(),取消 readObjectFromFile();//两个readObjectFromFile()方法的注释,再运行
//从文件中读数据(对象) public static void readObjectFromFile() throws Exception{ //1,创建对象输入流对象 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\15722\\Desktop\\a.txt")); //2,读取对象 Singleton instance = (Singleton) ois.readObject(); System.out.println(instance); //释放资源 ois.close(); }
public static void writeObject2File() throws Exception{ //1,获取Singleton对象 Singleton instance = Singleton.getInstance(); //2,创建对象输出流对象 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\15722\\Desktop\\a.txt")); //3,写对象 oos.writeObject(instance); //4,释放资源 oos.close(); } }
//这里的"C:\\Users\\15722\\Desktop"为桌面路径(根据自己的桌面路径进行更改),上面代码目的是在桌面创建一个a.txt文件
运行后我们桌面会生成一个a.txt文件,控制台输出如下:
同一个readObjectFromFile(),输出了两种结果(地址值不一样),表示两次从文件读到的对象不是同一个,已经破坏了单例模式.
序列化、反序列化破坏单例模式的解决方法:
在定义的Singleton类中添加readResolve()方法,在反序列化时被调用.如果定义了这个方法,就返回这个方法的值,如果没有定义,则返回新new出来的对象.
单例模式代码:
import java.io.Serializable; public class Singleton implements Serializable { //私有构造方法 private Singleton(){ } //定义一个静态内部类 private static class SingletonHolder{ //在内部类中声明并初始化外部类的对象 private static final Singleton INSTANCE = new Singleton(); } //提供公共的访问方式 public static Singleton getInstance(){ return SingletonHolder.INSTANCE; } //当进行反序列化时,会自动调用该方法,将该方法的返回值直接返回 public Object readResolve(){ return SingletonHolder.INSTANCE; } }
跟上面相比,多了个新定义的readResolve()方法.
测试类代码:
public class Client { public static void main(String[] args) throws Exception{ writeObject2File();//注意此处,先注释下面两个readObjectFromFile()方法,然后在运行 readObjectFromFile();//writeObject2File(),运行完后在注释writeObject2File(),取消 readObjectFromFile();//两个readObjectFromFile()方法的注释,再运行
//从文件中读数据(对象) public static void readObjectFromFile() throws Exception{ //1,创建对象输入流对象 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\15722\\Desktop\\a.txt")); //2,读取对象 Singleton instance = (Singleton) ois.readObject(); System.out.println(instance); //释放资源 ois.close(); }
public static void writeObject2File() throws Exception{ //1,获取Singleton对象 Singleton instance = Singleton.getInstance(); //2,创建对象输出流对象 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\15722\\Desktop\\a.txt")); //3,写对象 oos.writeObject(instance); //4,释放资源 oos.close(); } }
根据代码注释所说的步骤,重新运行一遍代码,结果如下:
我们可以发现,这两次从文件读取的对象的结果(地址值)是一样的,说明我们已经防止了经过序列化、反序列化后破坏了单例模式.