让我们来破坏单例模式

java中的单例模式经常会被问及作为单例的安全性,是否真正的能够实现实例的唯一性。正常情况下我们考虑是可以实现实例的唯一性的,如下单例:
public  class Singleton {
     public  static  final Singleton INSTANCE  =  new Singleton();
     private Singleton() {
    }
     public Singleton getInstance() {
         return  this.INSTANCE;
    }
}
上面的单例类可以返回唯一的实例。
但是我们引入(1)反射机制(2)序列化机制之后就会变得不同

一、反射机制的引入来破坏单例模式
下面是一个单例类,我们通过反射机制生成该类的一个实例。
import java.lang.reflect.Constructor;
public  class Singleton {
     public  static  final Singleton INSTANCE  =  new Singleton();
     private Singleton() {
    }
     public Singleton getInstance() {
         return INSTANCE;
    }
     public  static  void main(String[] args)  throws Exception {
         // 反射机制破坏单例模式
        Class clazz  = Singleton. class;
        Constructor c  = clazz.getDeclaredConstructor();
         // 反射机制使得private方法可以被访问!!!
        c.setAccessible(true);
         // 判断反射生成的对象与单例对象是否相等
        System.out.println(Singleton.INSTANCE  == c.newInstance());
    }
}
此时程序运行结果输出false,可以看出反射机制生成了新的对象,因此反射可以破坏单例模式。

二、序列化机制来破坏单例模式
序列化可以实现从字节码生成对象,因此序列化也有可能破坏单例模式
下面给出一个实现了序列化接口 Serializable 的单例类,看序列化如何生成单例类的一个实例
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public  class Singleton  implements Serializable {
     public  static  final Singleton INSTANCE  =  new Singleton();
     private Singleton() {
    }
     public  static  void main(String[] args)  throws Exception {
         // 支持java.io.Serializable的对象都可以写入流中
        ByteArrayOutputStream bos  =  new ByteArrayOutputStream();
        ObjectOutputStream oos  =  new ObjectOutputStream(bos);
        oos.writeObject(Singleton.INSTANCE);
         // 根据字节流生成对象
        ByteArrayInputStream bis  =  new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois  =  new ObjectInputStream(bis);
        Singleton newSingleton  = (Singleton) ois.readObject();
        System.out.println(newSingleton  == Singleton.INSTANCE);
    }
}
此时程序运行结果输出 false ,可以看出序列化机制生成了新的对象,因此反序列化的过程可以破坏单例模式。
不过可以通过引入 readResolve 方法来阻止反序列化过程中生成新的实例
如下
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public  class Singleton  implements Serializable {
     public  static  final Singleton INSTANCE  =  new Singleton();
     private Singleton() {
    }
     private Object  readResolve() {
         return INSTANCE;
    }
     public  static  void main(String[] args)  throws Exception {
         // 支持java.io.Serializable的对象都可以写入流中
        ByteArrayOutputStream bos  =  new ByteArrayOutputStream();
        ObjectOutputStream oos  =  new ObjectOutputStream(bos);
        oos.writeObject(Singleton.INSTANCE);
         // 根据字节流生成对象
        ByteArrayInputStream bis  =  new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois  =  new ObjectInputStream(bis);
        Singleton newSingleton  = (Singleton) ois.readObject();
        System.out.println(newSingleton  == Singleton.INSTANCE);
    }
}
此时程序返回true readResolve 方法使得在反序列化的过程中返回单例中的INSTANCE,而不是生成新的实例。 

你可能感兴趣的:(单例,singleton,反射,序列化,java,java)