Java代理類Proxy的用法


代理(proxy)

利用代理可以在運行時創建一個實現了一組給定接口的新類。這種功能只有在編譯時無法確定需要實現哪個接口時才有必要使用。

何時使用代理

假設有一個表示接口的Class對象(有可能只包含一個接口),它的確切類型在編譯時無法知道。要想構造一個實現這些接口的類,就需要使用newInstance方法或反射找出這個類的構造器。但是,不能實例化一個接口,需要在程序處於運行狀態時定義一個新類。

代理類可以在運行時創建全新的類。這樣的代理類能夠實現指定的接口。尤其是,它具有下列方法:

  • 指定接口所需要的全部方法
  • Object類中的全部方法,例如, toString, equals等。

創建代理對象

要想創建一個代理對象,需要使用Proxy類的newProxyInstance方法。這個方法有三個參數:

  • 一個類加載器(class loader)。
  • 一個Class對象數組,每個元素都是需要實現的接口。
  • 一個調用處理器

還有兩個需要解決的問題。如何定義一個處理器?能夠用結果代理對象做些什么?當然,這兩個問題的答案取決於打算使用代理機制解決什么問題。比如

  • 路由對遠程服務器的方法調用
  • 調試,跟蹤
  • log

Demo

我們定義一個處理器,用來打印調用的參數

public class TraceHandler implements InvocationHandler {

    private Object target;

    public TraceHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.print(target);
        System.out.print("." + method.getName() + "(");

        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                System.out.print(args[i]);
                if (i<args.length - 1){
                    System.out.print(", ");
                }
            }
        }

        System.out.println(")");

        return method.invoke(target, args);
    }
}

接下來,我們用它來代理Comparable接口,看看怎么調用。比如Arrays的二分查找方法binarySearch

    @Test
    public void traceBinarySearch() {
        Object[] elements = new Object[1000];

        for (int i = 0; i < elements.length; i++) {
            Integer value = i + 1;
            InvocationHandler handler = new TraceHandler(value);
            Object proxy = Proxy.newProxyInstance(null, new Class[]{Comparable.class}, handler);
            elements[i] = proxy;
        }

        Integer key = new Random().nextInt(elements.length) + 1;

        int result = Arrays.binarySearch(elements, key);

        if (result > 0) {
            System.out.println(elements[result]);
        }
    }

控制台打印結果:

500.compareTo(94)
250.compareTo(94)
125.compareTo(94)
62.compareTo(94)
93.compareTo(94)
109.compareTo(94)
101.compareTo(94)
97.compareTo(94)
95.compareTo(94)
94.compareTo(94)
94.toString()
94

代理類的特性

  • 代理類是在運行過程中創建的,創建完畢后和常規類相同,虛擬機同等對待。
  • 所有的代理類都擴展於Proxy類。一個代理類只有一個實例域---調用處理器,它定義在Proxy的超類中。
  • 沒有定義代理類的名字,Sun虛擬機中的Proxy類將生成一個以字符串$Proxy開頭的類名。
  • 對於特定的類加載器和預設的一組接口來說,只能有一個代理類。也就是說,如果使用同一個類加載器和接口數組調用兩次newProxyInstance方法的話,只能得到同一個類的兩個對象。比如class com.sun.proxy.$Proxy4.可以使用getProxyClass來獲取這個類。
  • 代理類一定是public final的。
  • 可以通過Proxy.isProxyClass方法檢測一個特定的Class對象是否代表一個代理類。

來源

  • Java核心技術


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM