JAVA的反射機制和動態代理(僅作記錄)


<反射機制>

    為了更好的理解java的反射機制,最好先對java的泛型有所了解。java泛型就是參數化類型,即為所操作的數據類型指定一個參數。如果只指定了<?>,而沒有extends,則默認是允許Object及其下的任何Java類。也就是任意類

1. Java運行時,對任意一個類,想知道它有哪些屬性和方法,對於任意一個對象,想調用它的任意一個方法,都是可以實現的,這來自JAVA的反射機制 

2. JAVA的反射機制主要功能: 
    (1)在運行時判斷任意一個對象所屬的類。 
    (2)在運行時構造任意一個類的對象。 
    (3)在運行時判斷任意一個類所具有的成員變量和方法。 
    (4)在運行時調用任意一個對象的方法 
    前提是在運行時,不是編譯時,也就是在運行前並不知道調用哪一個類,通過反射就可以做到這些 

3.在JDK中,主要由以下類來實現JAVA反射機制,這些類位於java.lang.reflect包中: 
    Class類:代表一個類 
    Field 類:代表類的成員變量(成員變量也稱為類的屬性)。 
    Method類:代表類的方法。 
    Constructor 類:代表類的構造方法。 
    Array類:提供了動態創建數組,以及訪問數組的元素的靜態方法 

4. Class類是Reflection API 中的核心類,它有以下方法 
    getName():獲得類的完整名字 
    getFields():獲得類的public類型的屬性 
    getDeclaredFields():獲得類的所有屬性 
    getMethods():獲得類的public類型的方法 
    getDeclaredMethods():獲得類的所有方法 
    getMethod(String name, Class[] parameterTypes):獲得類的特定方法,name參數指定方法的名字,parameterTypes 參數指定方法的參數類型 
    getConstructors():獲得類的public類型的構造方法 
    getConstructor(Class[] parameterTypes):獲得類的特定構造方法,parameterTypes 參數指定構造方法的參數類型 
    newInstance():通過類的不帶參數的構造方法創建這個類的一個對象 

 

<代理模式>

1. 代理模式的作用是:為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個客戶不想或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用

2. 代理模式一般涉及到的角色

(1)抽象角色:聲明真實對象和代理對象的共同接口

(2)代理角色:代理對象角色內部含有對真實對象的引用,從而可以操作真實對象,同時代理對象提供與真實對象相同的接口以便在任何時刻都能代替真實對象。同時,代理對象可以在執行真實對象操作時,附加其他的操作,相當於對真實對象進行封裝

(3)真實角色:代理角色所代表的真實對象,是我們最終要引用的對象

【實例】

Subject  抽象類  抽象角色 定義一個抽象方法request

RealSubject  真實角色  繼承了抽象類Subject 實現抽象方法request

ProxySubject  代理角色  同樣繼承抽象類Subject實現抽象方法request

Client  客戶端 

//抽象角色 abstract public class Subject{ abstract public void request(); }
//真實角色:實現了Subject的request()方法 public class RealSubject extends Subject{ public RealSubject(){ } public void request(){ System.out.println("局長辦事了!"); } }
//代理角色 public class ProxySubject extends Subject{ private RealSubject realSubject; // 以真實角色作為代理角色的屬性 public ProxySubject(){ }  // 該方法封裝了真實對象的request方法 public void request(){ preRequest(); if (realSubject == null){ realSubject = new RealSubject(); } realSubject.request(); // 此處執行真實對象的request方法 postRequest(); } private void preRequest(){ System.out.println("秘書去找局長"); } private void postRequest(){ System.out.println("秘書回來了"); } }
//客戶端調用
public class Client{
    public static void main(String[] args){
        Subject sub = new ProxySubject(); sub.request(); } }

在客戶端里,並沒有直接去調用真實對象中的request方法,但是卻實現了真實對象中的方法,是通過代理對象間接調用的,這里體現了代理模式的特點

1. 如果要按照上述的方法使用代理模式,那么真實角色必須是事先已經存在的,並將其作為代理對象的內部屬性。但是實際使用時,一個真實角色必須對應一個 代理角色,如果大量使用會導致類的急劇膨脹;此外,如果事先並不知道真實角色,該如何使用代理呢?這個問題可以通過Java的動態代理類來解決

2. 動態代理是指客戶通過代理類來調用其它對象的方法

3. Java動態代理類位於java.lang.reflect包下,一般主要涉及到以下兩個類: 

(1)Interface InvocationHandler:該接口中僅定義了一個方法 public object invoke(Object obj,Method method, Object[] args) 在實際使用時,第一個參數obj一般是指代理類,method是被代理的方法,如上例中的request(),args為該方法的參數數組。 這個抽象方法在代理類中動態實現。 

(2)Proxy:該類即為動態代理類,作用類似於上例中的ProxySubject

1. 動態代理的步驟

(1).創建一個實現接口InvocationHandler的類,它必須實現invoke方法

(2).創建被代理的類以及接口

(3).通過Proxy的靜態方法

newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 創建一個代理

(4).通過代理調用方法

 

package  net.xsoftlab.baike;
import  java.lang.reflect.InvocationHandler;
import  java.lang.reflect.Method;
import  java.lang.reflect.Proxy;
//定義項目接口
interface  Subject {
     public  String say(String name,  int  age);
}
// 定義真實項目
class  RealSubject  implements  Subject {
     public  String say(String name,  int  age) {
         return  name +  "  "  + age;
     }
}
class  MyInvocationHandler  implements  InvocationHandler {
     private  Object obj =  null ;
     public  Object bind(Object obj) {
         this .obj = obj;
         return  Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),  this );
     }
     public  Object invoke(Object proxy, Method method, Object[] args)  throws  Throwable {
         Object temp = method.invoke( this .obj, args);
         return  temp;
     }
}
/**
  * 在java中有三種類類加載器。
 
  * 1)Bootstrap ClassLoader 此加載器采用c++編寫,一般開發中很少見。
 
  * 2)Extension ClassLoader 用來進行擴展類的加載,一般對應的是jrelibext目錄中的類
 
  * 3)AppClassLoader 加載classpath指定的類,是最常用的加載器。同時也是java中默認的加載器。
 
  * 如果想要完成動態代理,首先需要定義一個InvocationHandler接口的子類,已完成代理的具體操作。
 
  * @author xsoftlab.net
 
  */
public  class  TestReflect {
     public  static  void  main(String[] args)  throws  Exception {
         MyInvocationHandler demo =  new  MyInvocationHandler();
         Subject sub = (Subject) demo.bind( new  RealSubject());
         String info = sub.say( "Rollen" 20 );
         System.out.println(info);
     }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM