Java編程思想——第14章 類型信息(二)反射
六、反射:運行時的類信息
我們已經知道了,在編譯時,編譯器必須知道所有要通過RTTI來處理的類。而反射提供了一種機制——用來檢查可用的方法,並返回方法名。區別就在於RTTI是處理已知類的,而反射用於處理未知類。Class類與java.lang.reflect類庫一起對反射概念進行支持,該類庫包含Field、Method以及Constructor(每個類都實現了Member接口)。這些類型是由JVM運行時創建的,用來表示未知類種對應的成員。使用Constructor(構造函數)創建新的對象,用get(),set()方法讀取和修改與Field對象(字段)關聯的字段,用invoke()方法調用與Method對象(方法)關聯的方法。這樣,匿名對象的類信息就能在運行時被完全確定下來,而在編譯時不需要知道任何事情。
其實,當反射與一個未知類型的對象打交道時,JVM只是簡單地檢查這個對象,在做其他事情之前必須先加載這個類的Class對象。因此,那個類的.class文件對於JVM來說必須時可獲取的(在本地或網絡上)所以反射與RTTI的區別只在於:對於RTTI來說,編譯器在編譯時打開和檢查.class文件,而對於反射來說,.class文件在編譯時是不可獲得的,所以是運行時打開和檢查.class文件。反射在需要創建更動態的代碼時很有用。
七、動態代理
代理是基本的設計模式:為其他對象提供一種代理,以便控制對象,而在對象前或后加上自己想加的東西。
interface Interface { void doSomething(); void doSomeOtherThing(String args); } class RealObject implements Interface { @Override public void doSomething() { System.out.println("doSomething"); } @Override public void doSomeOtherThing(String args) { System.out.println("doSomeOtherThing" + args); } } class SimpleProxy implements Interface { private Interface proxyId; public SimpleProxy(Interface proxyId) { this.proxyId = proxyId; } @Override public void doSomething() { //將原有的doSomething 方法添加上了一個輸出 這就是代理之後新增的東西 //就好比某公司代理遊戲后加的內購 System.out.println("SimpleProxy doSomething"); proxyId.doSomething(); } @Override public void doSomeOtherThing(String args) { proxyId.doSomeOtherThing(args); //新增的東西可以在原有之前或之後都行 System.out.println("SimpleProxy doSomeOtherThing" + args); } } public class SimpleProxyDemo { static void consumer(Interface i) { i.doSomething(); i.doSomeOtherThing(" yi gi woli giao"); } public static void main(String[] args) { consumer(new RealObject()); System.out.println("----- ----- -----"); consumer(new SimpleProxy(new RealObject())); } }
結果:
doSomething doSomeOtherThing yi gi woli giao ----- ----- ----- SimpleProxy doSomething doSomething doSomeOtherThing yi gi woli giao SimpleProxy doSomeOtherThing yi gi woli giao
因為consumer()接受的Interface,所以無論是RealObject還是SimpleProxy,都可以作為參數,而SimpleProxy插了一腳 代理了RealObject加了不少自己的東西。
java的動態代理更前進一步,因為它可以動態創建代理並動態地處理對所代理方法的調用。在動態代理上所做的所有調用都會被重定向到單一的調用處理器上,它的工作是揭示調用的類型並確定相應的對策。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface Interface { void doSomething(); void doSomeOtherThing(String args); } class RealObject implements Interface { @Override public void doSomething() { System.out.println("doSomething"); } @Override public void doSomeOtherThing(String args) { System.out.println("doSomeOtherThing" + args); } } class DynamicProxyHandler implements InvocationHandler { private Object proxyId; public DynamicProxyHandler(Object proxyId) { this.proxyId = proxyId; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("**** proxy:" + proxy.getClass() + ", method" + method + ", args:" + args); if (args != null) { for (Object arg : args) { System.out.println(" " + arg); } } return method.invoke(proxyId, args); } } public class SimpleProxyDemo { static void consumer(Interface i) { i.doSomething(); i.doSomeOtherThing(" yi gi woli giao"); } public static void main(String[] args) { RealObject realObject = new RealObject(); consumer(realObject); System.out.println("----- ----- -----");
//動態代理 可以代理任何東西 Interface proxy = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, new DynamicProxyHandler(realObject)); consumer(proxy); } }
結果:
doSomething doSomeOtherThing yi gi woli giao ----- ----- ----- **** proxy:class $Proxy0, methodpublic abstract void Interface.doSomething(), args:null doSomething **** proxy:class $Proxy0, methodpublic abstract void Interface.doSomeOtherThing(java.lang.String), args:[Ljava.lang.Object;@7ea987ac yi gi woli giao doSomeOtherThing yi gi woli giao
通過Proxy.newProxyInstance()可以創建動態代理,這個方法需要三個參數:
1. 類加載器:可以從已經被加載的對象中獲取其類加載器;
2. 你希望該代理實現的接口列表(不可以是類或抽象類,只能是接口);
3. InvocationHandler接口的一個實現;
在 invoke 實現中還可以根據方法名處對不同的方法進行處理,比如:
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("**** proxy:" + proxy.getClass() + ", method" + method + ", args:" + args); if (args != null) { for (Object arg : args) { System.out.println(" " + arg); } } if (method.getName().equals("doSomething")) { System.out.println("this is the proxy for doSomething"); } return method.invoke(proxyId, args); }
還可以對參數或方法進行更多的操作因為 你已經得到了他們 盡情的使用你的代理權吧 ~~ 先加它十個內購。
九、接口與類型信息
interface關鍵字的一種重要目標就是允許程序員隔離構件,進而降低耦合。反射,可以調用所有方法,甚至是private。唯獨final是無法被修改的,運行時系統會在不拋任何異常的情況接受任何修改嘗試,但是實際上不會發生任何修改。
void callMethod(Object a, String methodName) throws Exception { Method method = a.getClass().getDeclaredMethod(methodName); method.setAccessible(true); method.invoke(a); }
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!
※網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!
※想知道最厲害的台北網頁設計公司推薦、台中網頁設計公司推薦專業設計師”嚨底家”!!
※大陸寄台灣空運注意事項
※大陸海運台灣交貨時間多久?