一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - 淺談Java反射與代理

淺談Java反射與代理

2020-05-31 13:19java教程網 JAVA教程

下面小編就為大家帶來一篇淺談Java反射與代理。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

Java反射機制與動態代理,使得Java更加強大,Spring核心概念IoC、AOP就是通過反射機制與動態代理實現的。

1 Java反射

示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
User user = new User();
user.setTime5Flag("test");
 
Class<?> cls = Class.forName("com.test.User");
//接口必須public,無論是否在本類內部使用!或者使用cls.getDeclaredMethod(),或者遍歷修改可訪問性
Method method = cls.getMethod("getTime5Flag");
String res1 = (String) method.invoke(user);
System.out.println(res1);
//涉及到基本類型如int,則使用int.class!Integer.class!=int.class!
method = cls.getMethod("setTime5Flag", String.class);
method.invoke(user, "Rollen");
method = cls.getMethod("getTime5Flag");
String res2 = (String) method.invoke(user);
System.out.println(res2);

通過一個對象獲得完整的包名和類名:

?
1
2
user.getClass().getName();//全路徑類名
user.getClass().getSimpleName();//無包名的類名

獲取class:

?
1
2
3
Class.forName("com.test.User");
com.test.User.class;
user.getClass();
通過class實例化一個對象
?
1
User user = (User) cls.newInstance();//必須有無參構造函數
取得全部構造函數
?
1
2
Constructor<?> cons[]=cls.getConstructors(); //按聲明順序返回
cons[0].newInstance();//無顯示聲明,則有默認構造函數
取得一個類所實現的所有interface 
?
1
Class<?> intes[] = cls.getInterfaces();
取得父類
?
1
cls.getSuperClass();
取得修飾符
?
1
2
3
4
int mo = cls.getModifiers();
int mo = cons[0].getModifiers();
int mo = method.getModifiers();
Modifier.toString(mo);
獲取方法參數
?
1
2
method.getParametors();
cons[0].getParametors();
獲取方法參數類型
?
1
2
method.getParametorTypes();
cons[0].getParametorTypes();
獲取方法聲明拋出的所有異常類型
?
1
method.getExceptionTypes();
獲取本類聲明的全部屬性
?
1
2
3
Field[] field = cls.getDeclaredFields(); //包括private
field[0].getModifiers();
field[0].getType();

獲取本類的全部公開屬性,包括父類聲明、接口聲明、本類聲明的所有public屬性

?
1
cls.getFields();

設置指定屬性可訪問

?
1
2
3
field.setAccessible(true);
field.set(obj,'ces');
field.get(obj);

* getFields()與getDeclaredFields()區別:getFields()只能訪問類中聲明為公有的字段,私有的字段它無法訪問,能訪問從其它類繼承來的公有字段;getDeclaredFields()能訪問類中所有的字段,與public,private,protect無關,但不能訪問從其它類繼承來的字段

* getMethods()與getDeclaredMethods()區別:getMethods()只能訪問類中聲明為公有的方法,私有的方法它無法訪問,能訪問從其它類繼承來的公有方法;getDeclaredMethods()能訪問類中所有的字段,與public,private,protect無關,不能訪問從其它類繼承來的方法

* getConstructors()與getDeclaredConstructors()區別:getConstructors()只能訪問類中聲明為public的構造函數;getDeclaredConstructors()能訪問類中所有的構造函數,與public,private,protect無關

通過反射獲取并修改數組的信息

 

 

?
1
2
3
4
5
6
7
int[] temp={1,2,3,4,5};
Class<?> demo = temp.getClass().getComponentType();
System.out.println("數組類型: "+demo.getName());//int
System.out.println("數組長度: "+Array.getLength(temp));//5
System.out.println("數組的第一個元素: "+Array.get(temp, 0));//1
Array.set(temp, 0, 100);
System.out.println("修改之后數組第一個元素為: "+Array.get(temp, 0));//100
獲取數組類型
?
1
cls.getComponentType();
判斷是否是數組類型
 
?
1
cls.isArray();

2  Java代理

代理模式是常用的Java設計模式,它的特征是代理類與委托類有同樣的接口,代理類主要負責為委托類預處理消息、過濾消息、把消息轉發給委托類,以及事后處理消息等。代理類與委托類之間通常會存在關聯關系,一個代理類的對象與一個委托類的對象關聯,代理類的對象本身并不真正實現服務,而是通過調用委托類的對象的相關方法,來提供特定的服務。

按照代理的創建時期,代理類可以分為2種。

•靜態代理:由程序員創建或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。

•動態代理:在程序運行時,由Java反射機制動態生成字節碼。

2.1 靜態代理

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public interface Count {
  public void queryCount();
}
public class CountImpl implements Count {
  public void queryCount() {
    System.out.println("查看賬戶方法...");
  }
}
//代理類
public class CountProxy implements Count {
  private CountImpl countImpl; 
  public CountProxy(CountImpl countImpl) {
    this.countImpl = countImpl;
  
  @Override
  public void queryCount() {
    System.out.println("事務處理之前");     
    countImpl.queryCount(); // 調用委托類的方法;
    System.out.println("事務處理之后");
  }
//測試類
public class TestCount {
  public static void main(String[] args) {
    CountImpl countImpl = new CountImpl();
    CountProxy countProxy = new CountProxy(countImpl);
    countProxy.queryCount(); 
  }

觀察代碼可以發現每一個代理類只能為一個接口服務,這樣一來程序開發中必然會產生過多的代理,而且,所有的代理操作除了調用的方法不一樣之外,其他的操作都一樣,則此時肯定是重復代碼。解決這一問題最好的做法是可以通過一個代理類完成全部的代理功能,那么此時就必須使用動態代理完成。

2.2   動態代理

動態代理類的字節碼在程序運行時由Java反射機制動態生成,無需程序員手工編寫它的源代碼。動態代理類不僅簡化了編程工作,而且提高了軟件系統的可擴展性,因為Java 反射機制可以生成任意類型的動態代理類。

2.2.1  JDK動態代理

java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動態代理類的能力。

InvocationHandler接口:

public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}

參數說明:

Object proxy:指被代理的對象。
Method method:要調用的方法
Object[] args:方法調用時所需要的參數

可以將InvocationHandler接口的子類想象成一個代理的最終操作類,替換掉ProxySubject。

Proxy類:

Proxy類是專門完成代理的操作類,可以通過此類為一個或多個接口動態地生成實現類,此類提供了如下的操作方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

參數說明:

ClassLoader loader:類加載器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子類實例

如果想要完成動態代理,首先需要定義一個InvocationHandler接口的子類,以完成代理的具體操作。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
interface Subject {
  public String say(String name, int age);
}
class RealSubject implements Subject {
  @Override
  public String say(String name, int age) {
    return name + " " + age;
  }
}
//JDK動態代理類
class MyInvocationHandler implements InvocationHandler {
  private Object target = null;
  //綁定委托對象并返回一個代理類
  public Object bind(Object target) {
    this. target = target;
    return Proxy.newProxyInstance(target.getClass().getClassLoader(),
          target.getClass().getInterfaces(), this); //要綁定接口(cglib彌補了這一點)
  }
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println(“before method!”);
    Object temp = method.invoke(target, args);
    System.out.println(“after method!”);
    return temp;
  }
}
class hello {
  public static void main(String[] args) {
    MyInvocationHandler demo = new MyInvocationHandler();
    Subject sub = (Subject) demo.bind(new RealSubject());
    String info = sub.say("Rollen", 20);
    System.out.println(info);
  }
}

但是,JDK的動態代理依靠接口實現,如果有些類并沒有實現接口,則不能使用JDK代理,這就要使用cglib動態代理了。 

2.2.2  CGLIB動態代理

JDK的動態代理機制只能代理實現了接口的類,而未實現接口的類就不能實現JDK的動態代理。

cglib是針對類來實現代理的,它的原理是對指定的目標類生成一個子類,并覆蓋其中方法實現增強,但因為采用的是繼承,所以不能對final修飾的類進行代理。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public interface BookFacade {
  public void addBook();
}
public class BookFacadeImpl1 {
  public void addBook() {
    System.out.println("增加圖書的普通方法...");
  }
}
 
import java.lang.reflect.Method; 
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
//cglib動態代理類
public class BookFacadeCglib implements MethodInterceptor {
  private Object target; 
  //綁定委托對象并返回一個代理類
  public Object getInstance(Object target) {
    this.target = target;
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(this.target.getClass());
    // 回調方法
    enhancer.setCallback(this);
    // 創建代理對象
    return enhancer.create();
  
  @Override
  // 回調方法
  public Object intercept(Object obj, Method method, Object[] args,
      MethodProxy proxy) throws Throwable {
    System.out.println("事物開始");
    Object temp = proxy.invokeSuper(obj, args);
    System.out.println("事物結束");
    return temp; 
  }
}
public class TestCglib {
  public static void main(String[] args) {
    BookFacadeCglib cglib = new BookFacadeCglib();
    BookFacadeImpl1 bookCglib = (BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
    bookCglib.addBook();
  }
}

以上這篇淺談Java反射與代理就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持服務器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 性xxxx直播放免费 | 青草国产在线观看 | 男人天堂国产 | japanese人妖xvideos | 久久综久久美利坚合众国 | 成人天堂入口网站 | 亚洲精品综合一区二区 | 四虎影视在线永久免费观看 | 国产精品99久久免费观看 | 忘忧草秋观看未满十八 | 无码国产成人777爽死 | 色帝国亚洲欧美在线蜜汁tv | 久热人人综合人人九九精品视频 | 青青草在线观看 | 美女脱了内裤张开腿亲吻男生 | 国产露脸对白刺激3p在线 | 国内精品福利丝袜视频_速 国内精品91久久久久 | 婷婷日韩 | 亚洲一区 在线播放 | 亚洲精品久久久成人 | 欧美视频在线播放观看免费福利资源 | 网友自拍偷拍 | 含羞草传媒网站免费进入欢迎 | 国产原创一区二区 | 99视频都是精品热在线播放 | 亚洲精品九色在线网站 | 日本在线视频免费观看 | 男人的天堂在线观看视频不卡 | 国产在线麻豆波多野结衣 | 日本天堂影院在线播放 | 波多野结衣中文字幕 | www.毛片网站 | chinese老头和老太交hd | 成年人在线观看视频 | 欧美成人tv在线观看免费 | 国产精品夜夜爽张柏芝 | 干b视频在线观看 | 男人日女人的b | 天天综合色天天综合 | 甜性涩爱| juliaann大战两个黑人 |