日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

浅谈java代理

發(fā)布時間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅谈java代理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

【0】README

0.1) 本文描述+源代碼均 轉(zhuǎn)自 core java volume 1, 旨在理解 java代理機制 的基礎(chǔ)知識;


【1】代理相關(guān)

1.1)利用代理可以在運行時創(chuàng)建一個實現(xiàn)了一組給定接口的新類, 這種功能只有在 編譯時無法確定需要實現(xiàn)哪個接口時 才有必要使用;
1.2)假設(shè)有一個表示接口的 Class對象, 它的確切類型在編譯時無法知道。 要想構(gòu)造一個實現(xiàn)這些接口的類, 就需要使用 newInstance 方法或反射找出這個類的構(gòu)造器;但是不能實例化一個接口, 需要在程序處于運行狀態(tài)時定義一個新類;
1.3)解決問題的方法(代理機制): 代理機制是一種更好的解決方法。代理類可以在運行時創(chuàng)建全新的類, 這樣代理類能夠?qū)崿F(xiàn)指定的接口,尤其是, 它具有以下方法:

  • 1.3.1)指定接口所需要的全部方法;
  • 1.3.2) Object 類中的全部方法, 例如 , toString, equals等;
  • 1.3.3)然而,不能在運行時定義這些方法的新代碼。而是要提供一個 調(diào)用處理器(InvocationHandler), 該處理器是實現(xiàn)了 InvocationHandler 接口的類對象。在這個接口中只有一個方法: Object invoke(Object proxy, Method method, Object[] args) ; 要知道, 無論何時調(diào)用代理對象的方法, 調(diào)用處理器的invoke 方法都會被調(diào)用, 并向其傳遞Method對象和原始的調(diào)用參數(shù);

1.4)要想創(chuàng)建一個代理對象, 需要使用Proxy類的 newProxyInstance 方法, 該方法有3個參數(shù):

  • 1.4.1)一個類加載器:
  • 1.4.2)一個Class 對象數(shù)組: 每個元素都是需要實現(xiàn)的接口;
  • 1.4.3)一個調(diào)用處理器:
class TraceHandler implements InvocationHandlerInvocationHandler handler = new TraceHandler(value); Object proxy = Proxy.newProxyInstance(null, new Class[] { Comparable.class } , handler);

1.5)但是,還有兩個問題需要解決:
當(dāng)然了,這兩個問題的答案取決于打算使用代理機制解決什么問題。使用代理可能出于很多原因,如:

  • ex1)路由對遠程服務(wù)費去的方法調(diào)用;
  • ex2)在程序運行期間, 將用戶接口事件與動作關(guān)聯(lián)起來;
  • ex3)為調(diào)試, 跟蹤方法調(diào)用;

【2】看個荔枝(跟蹤方法調(diào)用):

public class ProxyTest {public static void main(String[] args){Object[] elements = new Object[1000];// fill elements with proxies for the integers 1 ... 1000for (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;}// construct a random integerInteger key = new Random().nextInt(elements.length) + 1;// search for the keyint result = Arrays.binarySearch(elements, key);// print match if foundif (result >= 0) System.out.println(elements[result]);} }class TraceHandler implements InvocationHandler {private Object target;public TraceHandler(Object t){target = t;}public Object invoke(Object proxy, Method m, Object[] args) throws Throwable{// print implicit argumentSystem.out.print(target);// print method nameSystem.out.print("." + m.getName() + "(");// print explicit argumentsif (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(")");// invoke actual methodreturn m.invoke(target, args);} }

2.1)打印結(jié)果:

【2】代理類的特性

2.1)需要記住: 代理類是在程序運行過程中創(chuàng)建的, 然而, 一旦被創(chuàng)建, 就變成了常規(guī)類,與虛擬機中的任何其他類沒有區(qū)別;
2.2)所有的代理類都擴展于 Proxy類。一個代理類只有一個實例域——調(diào)用處理器, 它定義在 Proxy的超類中, 為了履行代理對象的職責(zé), 所需要的任何附加數(shù)據(jù)都必須存儲在調(diào)用處理器中;
2.3)所有的代理類都覆蓋了 Object類中的方法 toString、equals 和 hashCode 方法;這些方法僅僅 調(diào)用了 調(diào)用處理器 的invoke 方法;Object類中的其他方法沒有被重新定義;
2.4)沒有定義代理類的名字的話, Sun 虛擬機中的Proxy類將生成一個 以 字符串 $Proxy 開頭的類名;
2.5)對于特定的類加載器和預(yù)設(shè)的一組接口來說, 只能有一個代理類;也就是說, 如果使用 同一個類加載器和接口數(shù)組調(diào)用兩次 newProxyInstance 方法的話, 那么只能夠得到同一個類的兩個對象, 也可以利用 getProxyClass 方法獲得這個類:

Class proxyClass = Proxy.getProxyClass(null, interfaces);

2.6)代理類一定是 public 和 final, 如果代理類實現(xiàn)的所有接口都是 public, 代理類就不屬于某個特定的包;否則,所有非公有的接口都必須屬于同一個包;
2.7)可以調(diào)用 Proxy類中的 isProxyClass 方法 檢測一個特定的 Class對象是否代表一個代理類;

[API] java.lang,reflect.InvocationHandler 1.3

Object invoke(Object proxy, Method method, Object[] args):返回實現(xiàn)指定接口的代理類; static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler handler) : 構(gòu)造一個實現(xiàn)指定接口的代理類的實例, 所有方法都將調(diào)用給定處理器對象的invoke 方法; static boolean isProxyClass(Class c) : 如果 c 是一個代理類返回 true

總結(jié)

以上是生活随笔為你收集整理的浅谈java代理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。