做爲Android開發你必須知道的Java反射機制

一.什麼是反射機制?

JAVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱爲java語言的反射機制.java


二.咱們須要知道哪些東西?

反射中咱們最常接觸到的類大體有一下幾個:數組

  • Class:
    Class對象是一個特殊的對象,是用來建立其它對象的對象(這裏的其餘對象就是指:java類的實例.其實Class對象就是java類編譯後生成的.class文件,它包含了與類有關的信息.
  • Field:
    Field字段提供有關和動態訪問的信息,類或接口的單個字段。反射的字段可能
    是類(靜態)字段或實例字段.
  • Method:
    Method方法提供了關於單個方法的信息和訪問在類或接口上。反射的方法多是類方法或者一個實例方法(包括一個抽象的方法).
  • Constructor:
    Constructor提供了關於某類的構造方法的所需信息.

三.咱們要掌握哪些方法呢?

  • 獲取Class對象的幾個方法:
    (1) 類名.class;
    (2) Class.forName(類路徑);
    (3) 對象.getClass();
    三個方法的區別是方法一不執行靜態塊和動態構造塊,方法二執行靜態塊、不執行動態構造塊,方法三須要建立對象,靜態塊和動態構造塊均會執行.
  • 獲取類屬性的幾個方法:
    (1) persionClass.getField(方法的名稱);
    (2) persionClass.getFields();
    (3) persionClass.getDeclaredField(方法的名稱);
    (4) persionClass.getDeclaredFields();複製代碼
    裏面getField和getFields只能獲取到public修飾的字段,getDeclaredField和getDeclaredFields能夠獲取到全部的字段.其中以s結尾的是獲取全部的字段返回的是一個Field 的數組.
  • 獲取類方法的幾個方法:
    (1) persionClass.getMethod(方法的名稱);
    (2) persionClass.getMethods();
    (3) persionClass.getDeclaredMethod(方法的名稱);
    (4) persionClass.getDeclaredMethods();複製代碼
    getMethod和getMethods只能獲取到public修飾的方法名稱,getDeclaredMethod和getDeclaredMethods能夠獲取到全部的方法.
  • 獲取構造函數的幾個方法:
    (1) persionClass.getConstructor(可變參數集合);
    (2) persionClass.getConstructors();
    (3) persionClass.getDeclaredConstructor(方法的名稱);
    (4) persionClass.getDeclaredConstructors();複製代碼
    getConstructor和getConstructors只能獲取到public修飾的方法名稱,getDeclaredConstructor和getDeclaredConstructors能夠獲取到全部的方法.
  • 建立對象的方法:bash

    (1) Constructor.newInstance(可變參數);
    
    eg:Persion p = (Persion)constructor.newInstance("1");複製代碼
  • 設置屬性值:
    (1) field.set(Objkect obj,Object value);
    (2) field.setInt(Objkect obj,int value);
    ...
    (n) file.setLong(Objkect obj,long value);複製代碼
  • 獲取屬性對象:ide

    (1) field.get(Object);
    
    eg:Person p = (Persion)filed.get(對象);複製代碼

    這裏要注意了若是字段的修飾符是Static的話裏面能夠傳入任何值包括null;函數

  • 調用方法:
    這裏必須注意的是當操做的對象用private修飾的時候須要用method.setAccessible(true)來設置能夠訪問到.而後調用method.invoke(Object obj,參數),這個Object的對象必須是該類的對象.不是所謂的類對象.ui


四.Android能用到的地方

  • 修改TabLayout的下劃線的長度.
    對於TabLayout的使用這裏就沒必要多說了,系統只提供了修改下劃線的高度和顏色的方法,並無修改長度的方法.這裏就要用到反射區獲取TabLayout內部控制長度的方法.這裏只能經過設置每一個Tab的Margin來控制下劃線的寬度,有可能出現Tab的文字被擠壓的狀況,只能將就使用了.代碼以下:
    Class<? extends TabLayout> tabClass = tabLayout.getClass();
         try {
             Field mTabStrip = tabClass.getDeclaredField("mTabStrip");
             mTabStrip.setAccessible(true);
            LinearLayout linearLayout = (LinearLayout) mTabStrip.get(tabLayout);
             for (int i = 0; i < linearLayout.getChildCount(); i++) {
                 View child = linearLayout.getChildAt(i);
                 child.setPadding(0,0,0,0);
                 LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) child.getLayoutParams();
                // layoutParams.width = 300;
                 layoutParams.leftMargin = 150;
                 layoutParams.rightMargin = 150;
                 child.setLayoutParams(layoutParams);
                 child.invalidate();
             }
         } catch (NoSuchFieldException e) {
             e.printStackTrace();
         } catch (IllegalAccessException e) {
             e.printStackTrace();
         }複製代碼
  • 控制Toast的顯示時間.
    Toast內部類TN的設置顯示時間的代碼:this

    mParams.hideTimeoutMilliseconds = mDuration ==
        Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
                     ...
        /**
          * schedule handleHide into the right thread
          */
         @Override
         public void hide() {
             if (localLOGV) Log.v(TAG, "HIDE: " + this);
             mHandler.obtainMessage(HIDE).sendToTarget();
         }複製代碼

    這裏系統自帶的Toast只給了咱們兩個時間的選擇SHORT_DURATION_TIMEOUT和LONG_DURATION_TIMEOUT其餘的咱們無法改變.還好系統提供了hide方法不過在外面咱們是訪問不到,這裏咱們也能夠用到反射,大部分的操做都是Toast的內部類TN來完成的.首先獲取到Toast的class對象,Toast內部含有內部類的字段(final TN mTN),這樣咱們能夠獲取到內部類的對象,而後再經過內部類的Class對象來獲取內部類裏面的hide()方法.代碼以下:spa

    try{
                     Class<Toast> toastClass = Toast.class;
                     Field mTN = toastClass.getDeclaredField("mTN");
                     //獲取修飾符類型
                     toastClass.getModifiers();
                     mTN.setAccessible(true);
                     Object o = mTN.get(toast);
                     Class<?> aClass = o.getClass();
                     Method hide = aClass.getDeclaredMethod("hide");
                     hide.setAccessible(true);
                     hide.invoke(o);
                 } catch (NoSuchFieldException e) {
                     e.printStackTrace();
                 } catch (IllegalAccessException e) {
                     e.printStackTrace();
                 } catch (InvocationTargetException e) {
                     e.printStackTrace();
                 } catch (NoSuchMethodException e) {
                     e.printStackTrace();
                 }複製代碼

    五.結束語

    反射對咱們來講仍是挺重要的,咱們不須要多麼的精通只須要在使用的時候不會那麼陌生.對於有java基礎的同窗學起來仍是比較容易的.code

    歡迎你們的觀看並提出寶貴的意見cdn

相關文章
相關標籤/搜索