有如下單例模式設計代碼:
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的構造函數,而是直接生成了兩個實例。
其實上面的代碼並沒有太大意義,只是作為知識點可以加深對反射和單例的理解和印象。
