Java中反射和Unsafe破坏单例设计模式
有如下单例模式设计代码:
class Singleton { private String info = "HELLO SHIT"; private static Singleton instance; private Singleton() { System.out.println("******实例化对象******"); } public static Singleton getInstance() { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } return instance; } public void show() { System.out.println("www.google.com"); } }
按照规则,我们只能获取一个实例化的对象,如下面的代码:
public class Hello { public static void main(String[] args) throws Exception { Singleton instanceA = Singleton.getInstance(); Singleton instanceB = Singleton.getInstance(); System.out.println(instanceA.hashCode()); System.out.println(instanceB.hashCode()); System.out.println(instanceA == instanceB); } }
程序输出:
******实例化对象****** 685325104 685325104 true Process finished with exit code 0
可以看到instanceA和instanceB完全相同.
下面演示用反射获取单例的构造函数,并且实例化出多个对象:
public class Hello { public static void main(String[] args) throws Exception { Constructor c = Singleton.class.getDeclaredConstructor(); c.setAccessible(true); Singleton instanceA = (Singleton)c.newInstance(); Singleton instanceB = (Singleton)c.newInstance(); System.out.println(instanceA.hashCode()); System.out.println(instanceB.hashCode()); System.out.println(instanceA == instanceB); } }
程序输出:
******实例化对象****** ******实例化对象****** 685325104 460141958 false Process finished with exit code 0
可以看到,这里调用了两次构造函数,实例化了两个不同的Singleton对象。
除了用反射,我们还可以用Unsafe类实例化多个单例对象,这种方式和反射的区别在于:Unsafe不需要调用构造函数。因为Unsafe是使用C++进行JVM底层控制。代码如下:
public class Hello { public static void main(String[] args) throws Exception { Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafeField.setAccessible(true); Unsafe unsafeInstance = (Unsafe)theUnsafeField.get(null); Singleton instanceA = (Singleton)unsafeInstance.allocateInstance(Singleton.class); Singleton instanceB = (Singleton)unsafeInstance.allocateInstance(Singleton.class); System.out.println(instanceA.hashCode()); System.out.println(instanceB.hashCode()); System.out.println(instanceA == instanceB); } }
程序输出:
460141958 1163157884 false Process finished with exit code 0
可以发现上面的代码根本没有调用Singleton的构造函数,而是直接生成了两个实例。
其实上面的代码并没有太大意义,只是作为知识点可以加深对反射和单例的理解和印象。