Java編程思想——第14章 類型信息(二)反射

6、反射:運行時的類信息

  咱們已經知道了,在編譯時,編譯器必須知道全部要經過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文件。反射在須要建立更動態的代碼時頗有用。程序員

7、動態代理

  代理是基本的設計模式:爲其餘對象提供一種代理,以便控制對象,而在對象前或後加上本身想加的東西。設計模式

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);
    }

還能夠對參數或方法進行更多的操做由於 你已經獲得了他們 盡情的使用你的代理權吧 ~~ 先加它十個內購。

9、接口與類型信息

  interface關鍵字的一種重要目標就是容許程序員隔離構件,進而下降耦合。反射,能夠調用全部方法,甚至是private。惟獨final是沒法被修改的,運行時系統會在不拋任何異常的狀況接受任何修改嘗試,可是實際上不會發生任何修改。

    void callMethod(Object a, String methodName) throws Exception {
        Method method = a.getClass().getDeclaredMethod(methodName);
        method.setAccessible(true);
        method.invoke(a);
    }
相關文章
相關標籤/搜索