java反射破壞單例模式

 一、 Java中的反射技術可以獲取類的所有方法、成員變量、還能訪問private的構造方法,這樣一來,單例模式中用的私有構造函數被調用就會產生多個實例,編寫代碼測試一下。

  1. package test;  
  2.   
  3. import java.lang.reflect.Constructor;  
  4.   
  5. public class SingetonTest {  
  6.   
  7.     private static SingetonTest singleton = null;  
  8.     private int s = 0;  
  9.       
  10.     // 構造方法是私有的  
  11.     private SingetonTest(){}  
  12.       
  13.     // 同步的獲取實例方法  
  14.     public static synchronized SingetonTest getInstance(){  
  15.         // 懶漢模式的單例方法  
  16.         if(null == singleton){  
  17.             singleton = new SingetonTest();  
  18.         }  
  19.         return singleton;  
  20.     }  
  21.       
  22.       
  23.     public int getS() {  
  24.         return s;  
  25.     }  
  26.   
  27.     public void setS(int s) {  
  28.         this.s = s;  
  29.     }  
  30.   
  31.     /** 
  32.      * @param args 
  33.      */  
  34.     public static void main(String[] args) {  
  35.         try {  
  36.             Constructor con = SingetonTest.class.getDeclaredConstructor();  
  37.             con.setAccessible(true);  //設置是否是可訪問的
  38.             // 通過反射獲取實例  
  39.             SingetonTest singetonTest1 = (SingetonTest)con.newInstance();  
  40.             SingetonTest singetonTest2 = (SingetonTest)con.newInstance();  
  41.             // 常規方法獲取實例  
  42.             SingetonTest singetonTest3 = SingetonTest.getInstance();  
  43.             SingetonTest singetonTest4 = SingetonTest.getInstance();  
  44.             // 測試輸出  
  45.             System.out.println("singetonTest1.equals(singetonTest2) :" +  singetonTest1.equals(singetonTest2));  
  46.             System.out.println("singetonTest3.equals(singetonTest4) :" +  singetonTest3.equals(singetonTest4));  
  47.             System.out.println("singetonTest1.equals(singetonTest3) :" +  singetonTest1.equals(singetonTest3));  
  48.             singetonTest1.setS(1);  
  49.             singetonTest2.setS(2);  
  50.             singetonTest3.setS(3);  
  51.             singetonTest4.setS(4);  
  52.             System.out.println("1:" + singetonTest1.getS() + "  2:" + singetonTest2.getS()+ "  3:" + singetonTest3.getS()+ "  4:" + singetonTest4.getS());  
  53.               
  54.         } catch (Exception e) {  
  55.             // TODO Auto-generated catch block  
  56.             e.printStackTrace();  
  57.         }  
  58.   
  59.     }  
  60.   
  61. }  
package test;

import java.lang.reflect.Constructor;

public class SingetonTest {

	private static SingetonTest singleton = null;
	private int s = 0;
	
	// 構造方法是私有的
	private SingetonTest(){}
	
	// 同步的獲取實例方法
	public static synchronized SingetonTest getInstance(){
		// 懶漢模式的單例方法
		if(null == singleton){
			singleton = new SingetonTest();
		}
		return singleton;
	}
	
	
	public int getS() {
		return s;
	}

	public void setS(int s) {
		this.s = s;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			Constructor con = SingetonTest.class.getDeclaredConstructor();
			con.setAccessible(true);
			// 通過反射獲取實例
			SingetonTest singetonTest1 = (SingetonTest)con.newInstance();
			SingetonTest singetonTest2 = (SingetonTest)con.newInstance();
			// 常規方法獲取實例
			SingetonTest singetonTest3 = SingetonTest.getInstance();
			SingetonTest singetonTest4 = SingetonTest.getInstance();
			// 測試輸出
			System.out.println("singetonTest1.equals(singetonTest2) :" +  singetonTest1.equals(singetonTest2));
			System.out.println("singetonTest3.equals(singetonTest4) :" +  singetonTest3.equals(singetonTest4));
			System.out.println("singetonTest1.equals(singetonTest3) :" +  singetonTest1.equals(singetonTest3));
			singetonTest1.setS(1);
			singetonTest2.setS(2);
			singetonTest3.setS(3);
			singetonTest4.setS(4);
			System.out.println("1:" + singetonTest1.getS() + "  2:" + singetonTest2.getS()+ "  3:" + singetonTest3.getS()+ "  4:" + singetonTest4.getS());
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}

測試結果:

singetonTest1.equals(singetonTest2) :false
singetonTest3.equals(singetonTest4) :true
singetonTest1.equals(singetonTest3) :false
1:1  2:2  3:4  4:4

通過反射技術生成的兩個實例不同,通過常規方法獲取的兩個實例相同(即同一個實例,單例)。


二、防止反射破壞單例模式,構造函數調用時進行處理,當構造函數第2次被調用時拋出異常!修改構造方法如下:

  1. private static boolean flag = false;  
  2.       
  3.     // 構造方法是私有的  
  4.     private SingetonTest(){  
  5.         if(flag){  
  6.             flag = !flag;  
  7.         }  
  8.         else{  
  9.             try {  
  10.                 throw new Exception("duplicate instance create error!" + SingetonTest.class.getName());  
  11.             } catch (Exception e) {  
  12.                 // TODO Auto-generated catch block  
  13.                 e.printStackTrace();  
  14.             }  
  15.         }  
  16.     }  
private static boolean flag = false;
	
	// 構造方法是私有的
	private SingetonTest(){
		if(flag){
			flag = !flag;
		}
		else{
			try {
				throw new Exception("duplicate instance create error!" + SingetonTest.class.getName());
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

三、一些思考

1)單例模式是爲了保證一個類只有一個實例,整個系統只能有自己創建的一個實例。應用在數據庫連接或單個隊列處理等問題。

2)單例模式構造,懶漢模式以時間換空間(用的時候才生產實例,每次都判斷);懶漢模式以空間換時間,直接創建實例,以後不用判斷直接用。

3)懶漢模式線程安全問題,獲取實例的方法要加上synchronized進行同步。

4)java的反射技術不要用於實例創建,反射主要用於spring的IOC,hibernate和白盒測試。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章