多態經過分離作什麼和怎麼作,從另外一個角度將接口與實現分離開來;經過多態來消除類型之間的耦合關係,在Java中,多態也叫動態綁定,後期綁定或運行時綁定,那麼什麼是方法綁定?java
將一個方法與調用同一個方法的主體關聯起來被稱爲綁定;若在程序執行前進行綁定(由編譯器和鏈接程序實現),叫作前期綁定;還有一種叫後期綁定,就是在運行時根據對象的類型進行綁定,也叫動態綁定或運行時綁定,也就是說,編譯器不知道對象的類型,可是方法調用機制能找到正確的方法體;在Java中除了static
方法和final
方法以外,全部的其餘方法都是後期綁定;編程
所以,Java中全部的方法都是經過動態綁定來實現多態的,但若是直接訪問某個域,則這個訪問就會在編譯其進行解析;通常咱們都經過將子類向上轉型爲父類來實現多態,父類能夠是抽象類,只要子類實現到父類的全部抽象方法,就能夠將子類轉型爲抽象的父類;Java裏的抽象類自己是不能被實例化,但能夠將子類的引用向上轉型爲抽象的父類。
如:ide
abstract class Jack{ public abstract void doSomething(); } class Product extends Jack{ @Override public void doSomething() { System.out.println("Product"); } } public static void main(String[] args) { //聲明一個抽象類Jack的變量,並指向其子類的實例化對象,合法的,Java的多態性會保證在運行時能夠獲得其正確的類型; Jack jack=new Product(); //Jack jack=new Jack();//非法,不能實例化抽象類對象 jack.doSomething(); }
Java反射機制是指在運行狀態時,能夠知道任意一個類的的全部屬性和方法,對任意一個對象均可以調用它的任意一個方法;經過反射,能夠在運行時實例化對象函數
Java反射提供的功能包括:this
咱們想獲得一個類的全部信息,第一步就是要獲得類的Class對象,若是知道了一個對象或類的名字,就能夠經過簡單的:
Class<?> clz=對象.getClass();
Class<?> clz=類的名字.class
獲得,但若是在編譯期得不到具體類型,則能夠經過Class.forName()
來獲得,但這個方法生成的結果在編譯時是不可知的,全部的方法特徵簽名都是在運行時提取出來的。這是由Java的反射機制來提供足夠的支持。在獲得這個類的Class對象後,咱們就能夠反射來構造對象,進而獲得這個類的全部的信息。代理
public static Class<?> forName(String className) throws ClassNotFoundException { Class<?> caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }
Java裏的Class
類與java.lang.reflect
類庫一塊兒對反射進行支持,該類庫包含了Field
,Method
,Constructor
類(每一個類都實現了Member
接口),這些類型的對象是在JVM在運行時建立的,用以表示未知類裏對應的成員。這樣咱們就可使用Constructor
建立新的對象,用get()
,set()
方法修改與Field對象關聯的字段,用invoke()
方法調用與Method
對象關聯的方法。(摘自《Java編程思想》第四版)code
下面簡要介紹利用反射實現的動態代理;對象
步驟:接口
InvocationHandler
接口,這個接口只有一個invoke()
方法;Proxy
類新建代理類對象;舉例:開發
interface Operate{ void method1(); void method2(); void method3(); } /** * 委託類 * @author wood * */ class Entrust implements Operate{ @Override public void method1() { // TODO Auto-generated method stub System.out.println("*method1"); } @Override public void method2() { // TODO Auto-generated method stub System.out.println("*method2"); } @Override public void method3() { // TODO Auto-generated method stub System.out.println("*method3"); } } /** * 鏈接委託類與代理類的中間類; * @author wood * */ class DynamecProxyHandler implements InvocationHandler{ private Object proxied;//委託類對象 public DynamecProxyHandler(){ } public DynamecProxyHandler(Object object){ this.proxied=object; } @Override public Object invoke(Object proxy, Method method, Object[] arg2) throws Throwable { // TODO Auto-generated method stub Object object=method.invoke(proxied, arg2); System.out.println(method.getName()); return object; } } //*********************** DynamecProxyHandler dymaProxy=new DynamecProxyHandler(new Entrust()); //經過Proxy類的靜態函數生成代理對象; Operate operate=(Operate)Proxy.newProxyInstance(Operate.class.getClassLoader(), new Class[]{Operate.class}, dymaProxy); operate.method1(); operate.method2(); operate.method3();
咱們經過Procy.newProcyInstance
函數新建了一個代理對象,實際的代理類就是在這時候動態生成了,咱們調用該代理對象的函數就會調用到中間類的invoke
函數,而invoke
函數實現調用委託類的對應函數;
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
loader
是類加載器;
interfaces
是委託類的接口,生成代理須要實現這個接口;
實際上Java的動態代理就是兩層的靜態代理:開發者提供一個委託類A,程序動態生成了一個代理類B,開發者還須要提供一個實現了InvocationHandler
的接口C,用類C來鏈接委託類A和委託類B,類C是代理類B的委託類,是類A的代理類;用戶直接調用代理類B,B將調用轉發給委託類C,C再將調用轉發給委託類A;
參考:
《Java編程思想》第四版
公共技術點之 Java 動態代理