乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      一篇文章全面了解Java反射機制

       路人甲Java 2020-06-13

      Java的反射機制在實踐中可謂無處不在,如果你已經(jīng)工作幾年,還對Java的反射機制一知半解,那么這篇文章絕對值得你讀一讀。

      什么是反射

      反射 (Reflection) 是Java的特征之一,它允許運行中的Java程序獲取自身的信息,并且可以操作類或?qū)ο蟮膬?nèi)部屬性。

      通俗的來講就是:通過反射機制,可以在運行時獲得程序或程序集中每一個類型的成員和成員的信息。

      注意這里的重點是:運行時,而不是編譯時。我們常規(guī)情況下寫的對象類型都是在編譯期就確定下來的。而Java反射機制可以動態(tài)地創(chuàng)建對象并調(diào)用其屬性,這樣創(chuàng)建對象的方式便異常靈活了。

      雖然通過反射可以動態(tài)的創(chuàng)建對象,增加了靈活性,但也不是什么地方都可用,還要考慮性能、編碼量、安全、面向?qū)ο笮缘取?/p>

      我們知道Java是面向?qū)ο蟮模绻ㄟ^反射機制去操作對象里面的屬性或方法,一定程度上破壞了面向?qū)ο蟮奶匦浴M瑫r,通過反射機制還可以修改私有變量,也存在一定的安全性問題。

      但這并不影響反射在實踐中的應用,幾乎各大框架多多少少都在使用Java反射機制。特別是主流的Spring框架。

      功能及用途

      Java反射主要提供以下功能:

      • 在運行時判斷任意一個對象所屬的類;
      • 在運行時構(gòu)造任意一個類的對象;
      • 在運行時判斷任意一個類所具有的成員變量和方法(通過反射甚至可以調(diào)用private方法);
      • 在運行時調(diào)用任意一個對象的方法

      反射最重要的用途之一就是開發(fā)各類通用框架。以Spring為例,當基于XML進行配置Bean時,我們通常寫如下代碼:

      <bean class="com.choupangxia.UserServiceImpl">
      </bean>
      

      Spring在啟動的時候便會利用反射機制去加載對應的UserServiceImpl類,然后進行實例化。如果不存在該類則會拋出異常,通常異常中還會出現(xiàn)invoke方法調(diào)用的堆棧信息。

      當Spring基于注解去實例化對象時,同樣利用的是反射機制。下面通過一個簡單demo示例,演示一下如何通過反射獲得注解信息:

      static void initUser(User user) throws IllegalAccessException {
      
      	// 獲取User類中所有的屬性(getFields無法獲得private屬性)
      	Field[] fields = User.class.getDeclaredFields();
      
      	// 遍歷所有屬性
      	for (Field field : fields) {
      		// 如果屬性上有此注解,則進行賦值操作
      		if (field.isAnnotationPresent(InitSex.class)) {
      			InitSex init = field.getAnnotation(InitSex.class);
      			field.setAccessible(true);
      			// 設(shè)置屬性的性別值
      			field.set(user, init.sex().toString());
      			System.out.println("完成屬性值的修改,修改值為:" + init.sex().toString());
      		}
      	}
      }
      

      上述代碼是之前寫《一篇文章,全面了解Java自定義注解》中的示例,相關(guān)文章可關(guān)注公眾號“程序新視界”,回復“注解”獲得全文。

      更多關(guān)于Java反射的例子我們就不多說了。上面的示例現(xiàn)在看不懂也沒關(guān)系,下面我們就來詳細介紹一下Java反射機制的具體使用。

      簡單示例

      我們通過一個簡單的示例對比,來了解一下Java反射機制。首先來看正常情況下創(chuàng)建對象并使用對象的示例:

      User user = new User();
      user.setUsername("公眾號:程序新視界");
      user.setAge(3);
      

      那么,當基于反射機制來達到統(tǒng)一效果該怎么做呢?看下面的具體實現(xiàn):

      @Test
      public void testCreateReflect() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
      		InvocationTargetException, InstantiationException {
      	// 獲取User所對應的Class對象
      	Class clz = Class.forName("com.choupangxia.reflect.User");
      	// 獲取User類無參數(shù)的構(gòu)造器
      	Constructor constructor = clz.getConstructor();
      	// 通過構(gòu)造器創(chuàng)建User對象
      	User user = (User) constructor.newInstance();
      	user.setUsername("公眾號:程序新視界");
      	user.setAge(3);
      	System.out.println("username=" + user.getUsername());
      	System.out.println("age=" + user.getAge());
      }
      

      在上述過程中通過Class.forName獲得User所對應的Class對象,獲得構(gòu)造器Constructor,通過構(gòu)造器創(chuàng)建出來一個User對象,然后調(diào)用對應的方法。

      當然,后面的步驟中也可以完全不出現(xiàn)User類,直接通過Class對象獲得對應的Method進行調(diào)用。示例如下:

      Method setUsernameMethod = clz.getMethod("setUsername", String.class);
      Method setAgeMethod = clz.getMethod("setAge", int.class);
      
      setUsernameMethod.invoke(obj,"公眾號:程序新視界");
      setAgeMethod.invoke(obj,3);
      

      關(guān)于get方法也是如此操作,就不再贅述。

      經(jīng)過上面的實例我們已經(jīng)能夠正常創(chuàng)建對象,并使用對象了。下面就看看反射常用的API,通過這些API我們可以實現(xiàn)更多的更復雜的功能。

      反射常用API

      獲取Class對象的三種方法

      第一種方法:當你知道類的全路徑名時,可使用Class.forName靜態(tài)方法來獲得Class對象。上面的示例就是通過這種方法獲得:

      Class clz = Class.forName("com.choupangxia.reflect.User");
      

      第二種方法:通過“.class”獲得。前提條件是在編譯前就能夠拿到對應的類。

      Class clz = User.class;
      

      第三種:使用類對象的getClass()方法。

      User user = new User();
      Class clz = user.getClass();
      

      創(chuàng)建對象的兩種方法

      可以通過Class對象的newInstance()方法和通過Constructor 對象的newInstance()方法創(chuàng)建類的實例對象。

      第一種:通過Class對象的newInstance()方法。

      Class clz = User.class;
      User user = (User) clz.newInstance();
      

      第二種:通過Constructor對象的newInstance()方法。

      Class clz = Class.forName("com.choupangxia.reflect.User");
      Constructor constructor = clz.getConstructor();
      User user = (User) constructor.newInstance();
      

      其中第二種方法創(chuàng)建類對象可以選擇特定構(gòu)造方法,而通過 Class對象則只能使用默認的無參數(shù)構(gòu)造方法。

      Class clz = User.class;
      Constructor constructor = clz.getConstructor(String.class);
      User user = (User) constructor.newInstance("公眾號:程序新視界");
      

      獲取類屬性、方法、構(gòu)造器

      通過Class對象的getFields()方法獲取非私有屬性。

      Field[] fields = clz.getFields();
      for(Field field : fields){
      	System.out.println(field.getName());
      }
      

      上述實例中的User對象屬性都是private,無法直接通過上述方法獲取,可將其中一個屬性改為public,即可獲取。

      通過Class對象的getDeclaredFields()方法獲取所有屬性。

      Field[] fields = clz.getDeclaredFields();
      for(Field field : fields){
      	System.out.println(field.getName());
      }
      

      執(zhí)行打印結(jié)果:

      username
      age
      

      當然針對屬性的其他值也是可以獲取的,針對私有屬性的修改需要先調(diào)用field.setAccessible(true)方法,然后再進行賦值。關(guān)于具體應用,回頭看我們最開始關(guān)于注解的實例中的使用。

      獲取方法的示例如下:

      Method[] methods = clz.getMethods();
      for(Method method : methods){
      	System.out.println(method.getName());
      }
      

      打印結(jié)果:

      setUsername
      setAge
      getUsername
      getAge
      wait
      wait
      wait
      equals
      toString
      hashCode
      getClass
      notify
      notifyAll
      

      可以看到,不僅獲取到了當前類的方法,還獲取到了該類父類Object類中定義的方法。

      關(guān)于獲取構(gòu)造器的方法上面已經(jīng)講到了,就不再贅述。而上述的這些方法在Class中都有相應的重載的方法,可根據(jù)具體情況進行靈活使用。

      利用反射創(chuàng)建數(shù)組

      最后,我們再看一個通過反射創(chuàng)建數(shù)組的實例。

      @Test
      public void createArray() throws ClassNotFoundException {
      	Class<?> cls = Class.forName("java.lang.String");
      	Object array = Array.newInstance(cls,5);
      	// 向數(shù)組添加內(nèi)容
      	Array.set(array,0,"Hello");
      	Array.set(array,1,"公眾號");
      	Array.set(array,2,"程序新視界");
      	Array.set(array,3,"二師兄");
      	Array.set(array,4,"Java");
      	// 獲取數(shù)組中指定位置的內(nèi)容
      	System.out.println(Array.get(array,2));
      }
      

      小結(jié)

      想必經(jīng)過上述的學習,對Java反射機制有了更進一步的了解,在最開始我們已經(jīng)說了反射機制也是有不足的。因此,如果可能盡量使用正統(tǒng)的寫法,但如果你在開發(fā)通用框架,則可考慮使用。

      后面,有機會我們再講解反射機制的源碼,別忘記關(guān)注公眾號:程序新視界。


      程序新視界:精彩和成長都不容錯過
      ![程序新視界-微信公眾號](https://img2020.cnblogs.com/other/1742867/202003/1742867-20200326074258111-1265370724.png)

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

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多