日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Java中的反射機制詳解

 oldzhoua 2019-04-10

一、什么是反射?

    在運行狀態(tài)中,對于任意一個類,都能夠獲取到這個類的所有屬性和方法,對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性(包括私有的方法和屬性),這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能就稱為java語言的反射機制。通俗點講,通過反射,該類對我們來說是完全透明的,想要獲取任何東西都可以。

    想要使用反射機制,就必須要先獲取到該類的字節(jié)碼文件對象(.class),通過字節(jié)碼文件對象,就能夠通過該類中的方法獲取到我們想要的所有信息(方法,屬性,類名,父類名,實現(xiàn)的所有接口等等),每一個類對應(yīng)著一個字節(jié)碼文件也就對應(yīng)著一個Class類型的對象,也就是字節(jié)碼文件對象。

獲取字節(jié)碼文件對象的三種方式。

1 Class clazz1 = Class.forName('全限定類名')

通過Class類中的靜態(tài)方法forName,直接獲取到一個類的字節(jié)碼文件對象,此時該類還是源文件階段,并沒有變?yōu)樽止?jié)碼文件。

2 Class clazz2  = Person.class

當(dāng)類被加載成.class文件時,此時Person類變成了.class,在獲取該字節(jié)碼文件對象,也就是獲取自己, 該類處于字節(jié)碼階段。

3 Class clazz3 = p.getClass()

通過類的實例獲取該類的字節(jié)碼文件對象,該類處于創(chuàng)建對象階段 

有了字節(jié)碼文件對象才能獲得類中所有的信息,我們在使用反射獲取信息時,也要考慮使用上面哪種方式獲取字節(jié)碼對象合理,視不同情況而定。下面介紹Class類的功能。

二、反射機制能夠獲取哪些信息

2.1 通過反射獲取類實例信息

//獲取字節(jié)碼文件Class clazz = Class.forName('com.demo.user');//創(chuàng)建User實例,這里是通過User的無參構(gòu)造函數(shù)來創(chuàng)建的User user = (User) clazz1.newInstance();

2.2 獲取指定構(gòu)造器方法

2.1說明了通過無參構(gòu)造器創(chuàng)建實例的方法,那如果只有有參的構(gòu)造器該如何創(chuàng)建實例呢?

// 獲取字節(jié)碼文件Class clazz = Class.forName('com.demo.User');// 先獲取有參構(gòu)造器,parameterTypes:表示參數(shù)列表,有多少寫多少,也可以不寫,不寫調(diào)用的就是無參構(gòu)造函數(shù)Construtor constructor = clazz.getConstructor(int.class, String.class);// 通過構(gòu)造器來實例化對象,將實際的參數(shù)傳進(jìn)去User user = (User) constructor.newInstance(18, '寶寶');

2.3 獲取全部構(gòu)造方法

Class clazz = Class.forName('com.demo.User');// 獲取所有構(gòu)造方法Constructor[] constructors = clazz.getConstructors();// 遍歷所有構(gòu)造方法for(int i = 0; i < constructors.length; i++) {  // 獲取每個構(gòu)造函數(shù)中得參數(shù)類型字節(jié)碼對象。  Class[] parameterTypes = constructors[i].getParameterTypes();  System.out.println('第'+i+'個構(gòu)造函數(shù)');  for(int j = 0; j < parameterTypes.length; j++) {   //獲取構(gòu)造函數(shù)中參數(shù)類型    System.out.print(parameterTypes[j].getName()+',');  }}

2.4 獲取類得所有成員變量

(1)、獲取指定成員變量

//獲取字節(jié)碼文件Class clazz = Class.forName('com.demo.User');//獲取實例對象User user = (User) clazz.newInstance();// 成員變量為非私有變量,使用getField(name)獲??;通過name來獲取指定成員變量Field field = clazz.getField('name');// 成員變量為私有屬性,獲得其屬性對象后,還要讓其打開可見權(quán)限Field field1 = clazz.getDeclaredField('id');field1.setAccessible(true);// 對其變量進(jìn)行賦值操作field1.setInt(user, 5);// 獲取成員變量得值System.out.println(field.getInt(user));

(2)、獲取全部成員變量

Class clazz = Class.forName('com.demo.User');User user = (User) clazz.newInstance();user.setId(13); // 賦值操作user.setName('寶寶'); // 賦值操作Field[] fields = clazz.getDeclaredFields(); // 將私有的屬性也一并獲得for(int i = 0; i<fields.length; i++) {  fields[i].setAccessible(true); // 將屬性(尤指私有屬性)的權(quán)限打開  System.out.println(fields[i].get(user)); //獲取成員變量的值}

2.5 獲得方法并使用 

Class clazz = Class.forName('com.demo.User');User user = (User) clazz.newInstance();// 不帶參數(shù)的方法, eat為不帶參數(shù)的public方法/***clazz.getMethod(name, parameterTypes)* name: 方法名* parameterTypes: 方法的參數(shù)類型的Class類型,沒有則什么都不填,比如參數(shù)為string,則填String.class*/Method method = clazz.getMethod('eat');// 調(diào)用方法/*** method.invoke(obj, args)* obj: 方法的對象* args: 實際的參數(shù)值,沒有則不填*/method.invoke(user);
// 帶參數(shù)的方法,sing為帶一個String類型參數(shù)的方法Method method1 = clazz.getMethod('sing', String.class);method1.invoke(user, '小明');
// 獲取私有的方法,和獲取私有屬性一樣,say為私有方法Method method2 = clazz.getDeclaredMethod('say');methods.setAccessible(true);method2.invoke(user);

2.6 獲取所有方法

Method[] methods = clazz.getDeclaredMethods();User user = (User) clazz.newInstance();for(Method method : methods) {  method.setAccessible(true);  System.out.ptintln(method.getName());  // 獲得方法的參數(shù),又回到了之前的代碼  Class<?> parameterTypes = method.getParameterTypes();  for(int j=0; j<parameterTypes.length; j++) {    // 獲取構(gòu)造函數(shù)中的參數(shù)類型    System.out.print(parameterTypes[j].getName()+',');  }}

2.7 獲得該類的所有接口

 Class[] getInterfaces():確定此對象所表示的類或接口實現(xiàn)的接口

 返回值:接口的字節(jié)碼文件對象的數(shù)組

2.8 獲取指定資源的輸入流

 InputStream getResourceAsStream(String name)  

 return:一個 InputStream 對象;如果找不到帶有該名稱的資源,則返回 null

 參數(shù):所需資源的名稱,如果以'/'開始,則絕對資源名為'/'后面的一部分。

2.9 動態(tài)代理的概述和實現(xiàn)

  動態(tài)代理:一種設(shè)計模式,其非常簡單,很容易理解,你自己可以做這件事,但是覺得自己做非常麻煩或者不方便,所以就叫一個另一個人(代理)來幫你做這個事情,而你就不用管了,這就是動態(tài)代理。舉個例子,買火車票叫人代買。 

  在程序運行過程中產(chǎn)生的這個對象,而程序運行過程中產(chǎn)生對象其實就是我們剛才反射講解的內(nèi)容,所以,動態(tài)代理其實就是通過反射來生成一個代理

  在Java中java.lang.reflect包下提供了一個Proxy類和一個InvocationHandler接口,通過使用這個類和接口就可以生成動態(tài)代理對象。JDK提供的代理只能針對接口做代理。我們有更強大的代理cglib,Proxy類中的方法創(chuàng)建動態(tài)代理類對象分三步,但是注意JDK提供的代理只能針對接口做代理,也就是下面的第二步返回的必須要是一個接口。

  1、new出代理對象,通過實現(xiàn)InvacationHandler接口,然后new出代理對象來。

  2、通過Proxy類中的靜態(tài)方法newProxyInstance,來將代理對象假裝成那個被代理的對象,也就是如果叫人幫我們代買火車票一樣,那個代理就假裝成我們自己本人

   3、執(zhí)行方法,代理成功

    將代理對象中的內(nèi)容進(jìn)行實現(xiàn)

public class MyInvocationHandler implements InvocationHandler{  private Object target;    public MyInvocationHandler(Object target) {    this.target = target;  }    @Override  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    System.out.println('權(quán)限校驗');    method.invoke(target, args);    System.out.println('日志打印');    return null;  }}
public interface Student{
public void login(); public void submit();}
@Overridepublic void login(){  System.out.println('登錄');}
@Overridepublic void submit() {  System.out.println('提交');}
MyInvocationHandler m = new MyInvocationHandler(si);Student s = (Student) Proxy.newProxyInstance(si.getClass().getClassLoader(), si.getClass().getInterfaces(), m);s.login();s.submit();

注意newProxyInstance的三個參數(shù),第一個,類加載器,第二個被代理對象的接口,第三個代理對象?! ?/p>

2.10 還有很多方法,比如獲得類加載器,等等

  具體還需要別的,就通過查看API文檔來解決。

三、反射機制的應(yīng)用是咧

3.1 利用反射,在泛型為int的arryaList集合中存放一個String類型的對象

   原理:集合中的泛型只在編譯器有效,而到了運行期,泛型則會失效

List<Integer> list = new ArrayList<Integer>;list.add(4);list.add(5);Class clazz = list.getClass();Method method = clazz.getMethod('add', Object.class);method.invoke(list, 'ddd');System.out.println(list);

四、總結(jié)

在我們?nèi)粘i_發(fā)中,反射用到的比較少,或者即使碰到也不知道這里是用反射實現(xiàn)的,了解反射的實現(xiàn)更利于我們寫代碼,這篇文章只介紹了反射的基本知識,更多使用場景在實際開發(fā)中遇到會更加好理解。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多