被破壞的單例模式
阿新 • • 發佈:2018-11-01
被破壞的單例模式
我們知道餓漢單例天生是執行緒安全的,但是通過其他途徑單例模式是可以被破壞的。懶漢亦如此。
1、通過反射來破解單例模式
打印出來的結果不一樣,說明這兩個物件就是不同的物件,這樣就破解了單例模式。
2、通過序列化和反序列化破解單例
readResolve()這個方法是基於回撥的,反序列化時,如果定義了readResolve()則直接返回此方法指定的物件,而不需要在建立新的物件。
每天努力一點,每天都在進步。
我們知道餓漢單例天生是執行緒安全的,但是通過其他途徑單例模式是可以被破壞的。懶漢亦如此。
1、通過反射來破解單例模式
public class Eagersingleton implements Serializable { private static final long serialVersionUID = 888L; private static Eagersingleton m_instance = new Eagersingleton();// 初始化時已經自行例項化 // 私有預設構造方法 private Eagersingleton() { } // 靜態工廠方法 public static Eagersingleton getInstance() { return m_instance; } }
public class Test1 { public static void main(String[] args) throws NoSuchMethodException, SecurityException { // 獲取單例物件 Eagersingleton instance = Eagersingleton.getInstance(); Eagersingleton instance2 = null; try { Class cls = Eagersingleton.class; Constructor constructor = cls.getDeclaredConstructor(null); // 關掉安全檢查,可以呼叫私有構造器 constructor.setAccessible(true); // 通過反射得到一個物件 instance2 = (Eagersingleton) constructor.newInstance(null); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(instance); System.out.println(instance2); } }
打印出來的結果不一樣,說明這兩個物件就是不同的物件,這樣就破解了單例模式。
解決方案:避免反射
2、通過序列化和反序列化破解單例
public class Test2 { public static void main(String[] args) throws FileNotFoundException, ClassNotFoundException { // 獲取單例物件 Eagersingleton instance = Eagersingleton.getInstance(); // 通過反序列化讀取物件 Eagersingleton instance2 = null; try { ObjectOutputStream oossStream = new ObjectOutputStream( new FileOutputStream("D:/EagersingletonTest.txt")); // 通過序列化把物件寫到檔案中 oossStream.writeObject(instance); oossStream.flush(); oossStream.close(); // 讀取檔案的物件 ObjectInputStream ois = new ObjectInputStream(new FileInputStream( "D:/EagersingletonTest.txt")); instance2 = (Eagersingleton) ois.readObject(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(instance); System.out.println(instance2); } }
打印出來的結果不一樣,說明這兩個物件就是不同的物件,破解了單例模式。
解決方案:避免序列化readResolve()這個方法是基於回撥的,反序列化時,如果定義了readResolve()則直接返回此方法指定的物件,而不需要在建立新的物件。
每天努力一點,每天都在進步。