1. 程式人生 > 實用技巧 >java牛客網錯題2020年9月3日

java牛客網錯題2020年9月3日

先看再點贊,給自己一點思考的時間,如果對自己有幫助,微信搜尋【程式職場】關注這個執著的職場程式設計師。
價值:Java技能,面試經驗指導,簡歷優化,職場規劃指導,技能提升方法,講不完的職場故事,個人成長經驗。


01

概念

動態代理是設計模式當中代理模式的一種。

主要用來做方法的增強,讓你可以在不修改原始碼的情況下,增強一些方法,在方法執行前後做任何你想做的事情,因為在InvocationHandler的invoke方法中,你可以直接獲取正在呼叫方法對應的Method物件,具體應用的話。


比如可以新增呼叫日誌,做事務控制等。

隨讓上面說了很多的有點,但是也是存在不足的。

誠然,Proxy已經設計得非常優美,但是還是有一點點小小的遺憾之處,那就是它始終無法擺脫僅支援interface

代理的桎梏,因為它的設計註定了這個遺憾。

回想一下那些動態生成的代理類的繼承關係圖,它們已經註定有一個共同的父類叫Proxy

Java的繼承機制註定了這些動態代理類們無法實現對class的動態代理,原因是多繼承在Java中本質上就行不通。

有很多條理由,人們可以否定對 class代理的必要性,但是同樣有一些理由,相信支援class動態代理會更美好。

介面和類的劃分,本就不是很明顯,只是到了Java中才變得如此的細化。

如果只從方法的宣告及是否被定義來考量,有一種兩者的混合體,它的名字叫抽象類。實現對抽象類的動態代理,相信也有其內在的價值。此外,還有一些歷史遺留的類,它們將因為沒有實現任何介面而從此與動態代理永世無緣。

如此種種,不得不說是一個小小的遺憾。但是,不完美並不等於不偉大,偉大是一種本質,Java動態代理就是佐例。

Jdk動態代理之所以只能代理介面是因為代理類本身已經extends了Proxy,而java是不允許多重繼承的,但是允許實現多個介面,因此才有這樣的需要。


終於知道為什麼說“Jdk動態代理侷限於介面是因為Java只支援單繼承”。

02

總結

1,JDK動態代理是基於介面的代理,其將代理介面中包括default方法在內的所有方法;

2,InvocationHandler是一個函式式介面(類似Runnable介面),其invoke方法指定方法的代理邏輯;

3,代理類的Method

屬性是介面中的方法物件,不是實現類的,註解加在介面方法上才能拿到;

03

使用步驟

1.通過實現InvocationHandler介面定義自己的InvocationHandler。

2.通過Proxy.getProxyClass0方法獲得動態代理類。

3.通過反射機制獲取動態代理類的構造方法,getConstructor(InvocationHandler.class)。

4.通過建構函式獲得代理物件,並將第一步時自定義的InvocationHandler例項物件作為入參,newInstance(new Object[]{InvocationHandler})。

5.通過代理物件呼叫方法。


04

實戰詳解

1.定義需要被動態代理的介面

public interface Subject {  void subjectRun(String param);}

2.被真正代理的類,用來處理實際業務

public class RealSubject implements Subject {  public void subjectRun(String param) {   
System.out.println("代理物件的方法被執行了!"+param);

}

}

3.定義代理類需實現InvocationHandler

public class ProxySubject implements InvocationHandler { //真正被代理的物件 
private Object subject;
//通過構造方法為代理物件賦值
public ProxySubject(Object subject){

this.subject = subject;
}

/**

* @param proxy 動態生成的代理類

* @param method 被代理的類的方法

* @param args 呼叫被代理類的入參

* @return
* @throws Throwable

*/@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("目標物件方法執行之前對方法加強!");
method.invoke(subject,args);
//subject:被代理的物件 args:呼叫方法的入參
System.out.println("目標物件方法執行之前對方法加強!");
return result;

}

}

4.測試類

public class ProxyRun {public static void main(String[] args){
//被真實代理的類,處理實際業務
Subject subject = new RealSubject();
//實現InvocationHandler的代理類
InvocationHandler h = new ProxySubject(subject); //動態生成代理類物件
Subject subjectProxy = (Subject)Proxy.newProxyInstance (h.getClass().getClassLoader(), subject.getClass().getInterfaces(),h);
 //呼叫動態生成代理類的方法
subjectProxy.subjectRun("execute");
}
}

5.程式執行結果

目標物件方法執行之前對方法加強!代理物件的方法被執行了!execute目標物件方法執行之後對方法加強!

05

實戰詳解


最後給大家來一個代理模式結構圖(來自網路)


我是【爾東雙月】一枚執著的職場程式設計師,微信搜尋【程式職場】關注我。別忘了三連啊,點贊、收藏、留言,隨意給,我不挑。
知乎號: 程式職場
CSDN:程式職場
注:如果文章有任何問題,歡迎毫不留情地指正。