咱們已經知道了,在編譯時,編譯器必須知道全部要經過RTTI來處理的類。而反射提供了一種機制——用來檢查可用的方法,並返回方法名。區別就在於RTTI是處理已知類的,而反射用於處理未知類。Class類與java.lang.reflect類庫一塊兒對反射概念進行支持,該類庫包含Field、Method以及Constructor(每一個類都實現了Member接口)。這些類型是由JVM運行時建立的,用來表示未知類種對應的成員。使用Constructor(構造函數)建立新的對象,用get(),set()方法讀取和修改與Field對象(字段)關聯的字段,用invoke()方法調用與Method對象(方法)關聯的方法。這樣,匿名對象的類信息就能在運行時被徹底肯定下來,而在編譯時不須要知道任何事情。java
其實,當反射與一個未知類型的對象打交道時,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加了很多本身的東西。ide
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); } }
結果:this
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()能夠建立動態代理,這個方法須要三個參數:spa
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); }