Java基礎---反射和代理

之前參與一個項目,使用的技術框架是struts2+ibatis,業餘好奇探索了下,於是有幸接觸到java的反射和動態代理。我知道在struts2的攔截器中使用了反射和動態代理,據說很多經典的框架,比如spring、hibernate、ibatis等也都大範圍使用了。這兩種技術大概意思如下:

反射:在程序運行的時候,動態的獲取某個類中的屬性和方法,並且能夠調用(很多框架能自動識別你寫的類,然後調用一些共同的方法,靠的就是它)。

代理:給類包裝上一層殼,通過這個殼去操作這個類,使得你在操作這個類之前之後可以做一些你想做的事情。

 

反射介紹

反射比較簡單,主要使用Class類,Class類提供了運行時獲取或調用某個類具體內容的方法。如下代碼作實例:

待調用的類MyClass:

[java] view plaincopy
  1. public class MyClass {  
  2.     private int myInt;  
  3.     private String myString;  
  4.   
  5.     public MyClass(){  
  6.   
  7.     }  
  8.   
  9.     public MyClass(int a){  
  10.         this.myInt = a;  
  11.     }  
  12.   
  13.     public void Method2Void(){  
  14.   
  15.     }  
  16.   
  17.     public int Method2Int(){  
  18.         System.out.println("Method2Int has run");  
  19.         return 0;  
  20.     }  
  21.   
  22.     public String Method2String(){  
  23.         return "";  
  24.     }  
  25.   
  26.     public Object Method2Object() {  
  27.         return new Date();  
  28.     }  
  29.   
  30.     public void Method3Param(int a, String b){  
  31.         System.out.println("Method3Param has run with param-a:" + a + " and param-b:" + b);  
  32.     }  
  33. }  

Main函數
[java] view plaincopy
  1. public static void main(String[] args){  
  2.     MyClass myClass = new MyClass();  
  3.     Class cls = myClass.getClass();//獲取一個類的Class  
  4.   
  5.     System.out.println("1:" + cls.getName());//名字  
  6.     System.out.println("2:" + cls.getSimpleName());  
  7.     System.out.println("3:" + cls.getPackage());  
  8.     try{  
  9.         Method m = cls.getMethod("Method2Int"new Class[]{});//獲取一個類的方法  
  10.         m.invoke(myClass, new Object[]{});//精髓所在,調用這個類的方法  
  11.   
  12.         Method m2 = cls.getMethod("Method3Param"new Class[]{int.class, String.class});  
  13.         m2.invoke(myClass, new Object[]{5"fake"});//調用這個類的方法,帶參數的  
  14.     }catch(Exception e){  
  15.         e.printStackTrace();  
  16.     }  
  17.     Method[] ms = cls.getMethods();  
  18.   
  19.     for(Method m:ms){  
  20.         System.out.println(m.getName());  
  21.     }  
  22.   
  23.   
  24.     try{  
  25.         Class cls2 = Class.forName("MyClass");//這種方法也能獲取一個類的Class,同時能動態載入這個類  
  26.     }catch(Exception e){  
  27.         e.printStackTrace();  
  28.     }  
  29. }  


下面詳細介紹下代理

      代理這種現象在生活中是非常常見的,比如你要買火車票,可以讓你的朋友幫你買,也可以託代售點幫你買。你把錢給了他們,他們可能會做任何事情。也許你朋友忘記;或者代售點把你黑了。當然,程序是你的,你可以控制他們的行爲。

      代理有普通代理和動態代理。上面說的你的朋友,可以看成是普通代理,代售點可以看成是動態代理。區別在於,你的朋友並不會幫每個人都買票,僅僅幫他認識少部分人買,而代售點是來者不拒的,具有通用性。

      使用代理模式,需要區分真實對象和代理對象。代理對象中含有真實對象的引用,可以對真實對象進行操作,調用真實對象的方法。可以通過調用代理對象的方法,間接的去調用真實對象的方法。

下面還是舉例來說說這兩種代理吧。

以下是這兩種代理所需的類:

行爲PersonAct.java

[java] view plaincopy
  1. package proxy;  
  2.   
  3. public interface PersonAct {  
  4.     void buyTicket();//買票  
  5.     void checkProperty();//查看財產  
  6. }  

抽象類Person.java

[java] view plaincopy
  1. import java.util.Map.Entry;  
  2.   
  3. public abstract class Person implements PersonAct{  
  4.     //全部家當放在這個HashMap裏  
  5.     HashMap<String, Object> property = new HashMap<String, Object>();  
  6.       
  7.     String name;  
  8.       
  9.     public Person(String name, int money){  
  10.         this.name= name;  
  11.         this.property.put("money", money);  
  12.     }  
  13.       
  14.     //打印目前家當  
  15.     public void checkProperty(){  
  16.         System.out.println(this.name + "的家當如下:");  
  17.         Iterator<Entry<String, Object>> iter = property.entrySet().iterator();  
  18.         while(iter.hasNext()){  
  19.             Entry<String, Object> entry = (Entry<String, Object>)iter.next();  
  20.             System.out.println(entry.getKey() + "---" + entry.getValue());  
  21.         }          
  22.     }             
  23. }  

真實類Boy.java

[java] view plaincopy
  1. package proxy;  
  2.   
  3. public class Boy extends Person{  
  4.       
  5.     public Boy(String name, int money){  
  6.         super(name, money);  
  7.     }  
  8.       
  9.     //買票  
  10.     @Override  
  11.     public void buyTicket() {  
  12.         int money = (Integer)property.get("money");  
  13.           
  14.         property.put("money", money - 38);//扣錢  
  15.         property.put("ticket""北京到上海機票");//拿票          
  16.     }  
  17. }  

真實類Girl.java

[java] view plaincopy
  1. package proxy;  
  2.   
  3. public class Girl extends Person{  
  4.       
  5.     public Girl(String name, int money){  
  6.         super(name, money);  
  7.     }      
  8.       
  9.     @Override  
  10.     public void buyTicket() {  
  11.         int money = (Integer)property.get("money");  
  12.           
  13.         property.put("money", money - 46);//扣錢  
  14.         property.put("ticket""北京到深圳機票");//拿票      
  15.     }          
  16. }  

上面的類Boy和Girl代表現實生活中的兩個人,Boy自己去買票的過程如下。

[java] view plaincopy
  1. Boy boy = new Boy("西門慶"100);          
  2. boy.checkProperty();  
  3. boy.buyTicket();  
  4. boy.checkProperty();  

結果將會打印出boy購票前和投票後的家當。

1,普通代理

類FatherOfBoy.java

[java] view plaincopy
  1. package proxy;  
  2.   
  3. public class FatherOfBoy {  
  4.     private Boy boy = new Boy("西門慶"100);  
  5.       
  6.     public void buyTicket(){  
  7.         boy.buyTicket();  
  8.     }  
  9.       
  10.     public void checkProperty(){  
  11.         boy.checkProperty();  
  12.     }  
  13. }  

概念很好理解,普通代理買票可以這樣測試。

[java] view plaincopy
  1. FatherOfBoy father = new FatherOfBoy();  
  2. father.checkProperty();  
  3. father.buyTicket();  
  4. father.checkProperty();  

2,  動態代理

動態代理主要通過繼承InvocationHandler接口來實現。

ProxyAgency.java如下:

[java] view plaincopy
  1. package proxy;  
  2.   
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.Method;  
  5.   
  6. public class ProxyAgency implements InvocationHandler{  
  7.     private Person target;//真實對象的引用  
  8.       
  9.     public void setTarget(Person target) {  
  10.         this.target = target;  
  11.     }  
  12.   
  13.     public ProxyAgency(){  
  14.           
  15.     }  
  16.       
  17.     public ProxyAgency(Person obj){  
  18.         this.setTarget(obj);  
  19.     }  
  20.       
  21.     //obj,這個是代理對象  
  22.     //method,具體調用的方法  
  23.     //args,調用方法的時候傳進來的參數,一般都直接傳給真實對象即可  
  24.     @Override  
  25.     public Object invoke(Object obj, Method method, Object[] args) throws Throwable {  
  26.         //target,真實對象,收取手續費10元  
  27.         if(method.getName().equalsIgnoreCase("buyTicket")){  
  28.             int money = Integer.parseInt(target.property.get("money").toString());  
  29.             target.property.put("money", money - 10);  
  30.         }  
  31.         //target,真實對象,下面一句屬於java反射機制的東西,用反射機制獲取真實對象的方法          
  32.         return method.invoke(target, args);//調用真實對象的方法  
  33.     }  
  34. }  

調用實例:


[java] view plaincopy
  1.         //代理對象構建器  
  2.         ProxyAgency proxyAgency = new ProxyAgency();  
  3.           
  4.         //真實對象  
  5.         Boy b = new Boy("西門慶"100);  
  6.         Girl g = new Girl("潘金蓮"200);          
  7.           
  8.         //代理對象,獲取方法1  
  9.         PersonAct p1 = (PersonAct) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{ PersonAct.class }, proxyAgency);  
  10.           
  11.         //真實對象注入構建器,也可以在構建器的構造函數中注入  
  12.         proxyAgency.setTarget(b);          
  13.           
  14.           
  15.         //代理對象獲取方法2  
  16. //        Class<?> cls = g.getClass();  
  17. //        PersonAct p1 = (PersonAct) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), proxyAgency);  
  18.           
  19.         p1.checkProperty();  
  20.         p1.buyTicket();  
  21.         p1.checkProperty();  
  22.           
  23.         proxyAgency.setTarget(g);  
  24.           
  25.         p1.checkProperty();  
  26.         p1.buyTicket();  
  27.         p1.checkProperty();  

輸出如下:

西門慶的家當如下:
money---100
西門慶的家當如下:
ticket---北京到上海機票
money---52
潘金蓮的家當如下:
money---200
潘金蓮的家當如下:
ticket---北京到深圳機票
money---144



出處:http://blog.csdn.net/weinianjie1/article/details/6722743

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