1. 程式人生 > >Java反射實現介面

Java反射實現介面

轉自: http://blog.csdn.net/lastwarmth/article/details/49466899

之前做過一個外掛,綜合了移動MM,移動和遊戲,沃商店等一些計費SDK。將這些計費SDK提供的介面全部整合,最後由外掛提供一套介面。通過後臺配置,來讓遊戲使用某種計費SDK。遊戲開發商接入計費的時候,只需要呼叫外掛提供的一套介面即可。因為不可能保證遊戲會包含所有的計費SDK的程式碼,所以外掛內部只能利用反射來實現。通過反射來獲取類,獲取方法進行呼叫是比較簡單的。

但是有個問題困擾了我很久:計費SDK都有提供回撥介面,使遊戲開發商在計費成功或失敗進行回撥,那麼如何通過反射來實現這些回撥介面,進行呼叫呢?通過一段時間的摸索,知道了一種解決方法:使用Proxy

類與InvocationHandler介面。

下面通過一個例子進行講解。 
1、首先以計費SDK為例子寫一個library工程,提供一個方法和一個回撥介面:

package com.lastwarmth.library;

public class MyLibrary {

    public interface Callback {
        void doCallback();
    }

    public void mainMethod(Callback callback) {
        System.out.println("doing main...");
        callback.doCallback();
    }
}
2、新建MyTest工程,編寫類實現InvocationHandler:
package com.lastwarmth.demo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyHandler implements InvocationHandler{

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("doing callback...");
        return null;
    }

}
3、MyTest工程測試程式碼:
package com.lastwarmth.demo;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyTest {

    public static void main(String[] args) {
        try {
            Class<?> mClass = Class.forName("com.lastwarmth.library.MyLibrary");
            Class<?> mCallback = Class.forName("com.lastwarmth.library.MyLibrary$Callback");
            MyHandler mHandler = new MyHandler();
            Object mObj = Proxy.newProxyInstance(MyTest.class.getClassLoader(), new Class[] { mCallback }, mHandler);
            Method mMethod = mClass.getDeclaredMethod("mainMethod", new Class[] { mCallback });
            mMethod.invoke(mClass.newInstance(), new Object[] { mObj });
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException 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();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}
4、將MyLibrary打成jar包,引入到MyTest的build path中,或者直接將Java程式碼考到MyTest工程下(若不這樣做,執行會丟擲異常,但不會致使程式崩潰)。然後執行,控制檯輸出結果:
doing main...
doing callback...
說明MyTest類通過反射獲取到了MyLibrary類中的Callback介面,並實現呼叫。 
程式碼比較簡單,就不作過多講述了

總結: 
java.lang.reflect.Proxy:這是 Java 動態代理機制的主類,它提供了一組靜態方法來為一組介面動態地生成代理類及其物件

  • static InvocationHandler getInvocationHandler(Object proxy):該方法用於獲取指定代理物件所關聯的呼叫處理器

  • static Class getProxyClass(ClassLoader loader, Class[] interfaces) :該方法用於獲取關聯於指定類裝載器和一組介面的動態代理類的類物件

  • static boolean isProxyClass(Class cl):該方法用於判斷指定類物件是否是一個動態代理類

  • static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):該方法用於為指定類裝載器、一組介面及呼叫處理器生成動態代理類例項 

  • 文中採用第4個方法,獲取到了實現介面Callback的例項。

java.lang.reflect.InvocationHandler:這是呼叫處理器介面,它自定義了一個 invoke 方法,用於集中處理在動態代理類物件上的方法呼叫,通常在該方法中實現對委託類的代理訪問。

  • Object invoke(Object proxy, Method method, Object[] args):該方法負責集中處理動態代理類上的所有方法呼叫。第一個引數是代理類例項,第二個引數是被呼叫的方法物件。第三個方法是呼叫引數。呼叫處理器根據這三個引數進行預處理或分派到委託類例項上反射執行。

在本文中,並沒有代理類。直接在invoke方法中寫入我們繼承Callback介面需要實現的方法內容即可。 
通過Proxy類與InvocationHandler介面,即可完成反射實現介面的功能了。