夯實 Java 基礎 - 反射

夯實 Java 基礎 - 反射

自嵌套 Fragment 懶加載文章至今已經已經一個星期過去了,說實話最近對於學習的熱情有點衰減,也多是本身有點飄了,也有多是現實中的誘惑多了點,可是這是個很差的狀態,必須調整本身向着目標繼續前進。java

前言

本文將重拾 Java 基礎中的反射知識,因爲筆者是作移動端 Android 開發的,平常工做中反射用的少的能夠拿手指頭數過來。如今我所記得的上次使用它應該是在修改 TabLayout 的下劃線寬度的時候。此次重拾反射這部分知識的主要緣由實際上是在註解和動態代理。相比反射來講這二者在咱們平常使用的框架中比較常見,好比 EventBus 原理,ButterKnife 原理,Retrofit原理,甚至 AOP(面向切面編程) 在 Android 中的應用,都有這二者的身影。android

本文其實沒有什麼養分價值,和其餘相關文章同樣,本文更多的是在記錄反射的 API,這麼作更多多是爲了之後遺忘了方便查閱。本文將從如下幾個方面來記錄:編程

  1. 反射是什麼? 反射的意義?
  2. 反射的入口 - Class 類
  3. 反射的成員變量獲取 - Field 類
  4. 反射的方法獲取 - Method 類
  5. 反射的構造方法獲取 - Constructor 類
  6. 反射的獲取註解相關信息

反射機制

試着解釋清楚爲何須要反射是並不簡單,這裏涉及了一些 jvm 類加載機制,那麼從先前說的修改 TabLayout 的下劃線寬度提及,首先 TabLayout 是存在 SDK 中並非咱們定義的一個類,可是在使用中咱們遇到了要修改其內容的需求,這時候咱們經過反射在程序運行時獲取了其內部私有變量 mTabStrip ,並修改了他的 LayoutParams。咱們知道咱們經過 tablayout.mTabStrip 是沒法訪問的,由於變量是私有的。數組

Field tabStrip = tablayout.getDeclaredField("mTabStrip");
tabStrip.setAccessible(true);
...
do reset padding LayoutParams operation
複製代碼

固然這只是我遇到的一個使用場景,作 JavaWeb 的朋友應該對此有更深的瞭解。框架

那麼這裏記錄下什麼是反射的官方說法:jvm

經過反射,咱們能夠在運行時得到程序或程序集中每個類型的成員和成員的信息。Java 反射機制能夠動態地建立對象並調用其屬性,即便這個對象的類型在編譯期是未知的。函數

經過 Java 的反射機制咱們能夠:post

  1. 在運行時判斷任意一個對象所屬的類;
  2. 在運行時構造任意一個類的對象;
  3. 在運行時獲取任意一個類所具備的成員變量和方法,即便它是私有的;
  4. 在運行時調用任意一個對象的方法;

注意咱們所提到的前提和重點是運行時。學習

反射的入口 - Class 類

如何獲取 Class 類

想要經過反射操做一個類的成員或者方法,Java 爲咱們提供了一套 API 而這套 API 屬於 Class 類,做爲一些列反射操做的入口,Java 提供了三個方法或得到某個對象或者類的 Class 類對象:測試

  • 使用 Object 的 getClass 方法,如咱們已知一個類的對象咱們可使用超類的 getClass 方法獲取:
TabLayout tabLayout = findViewById(R.id.tabLayout);
Class<?> tabLayoutClass = tabLayout.getClass();
複製代碼
  • 咱們也能夠經過 XXX.class 的方式直接獲取某個類的 Class 對象而無需建立該類的對象。
//對於普通引用數據類型的類咱們能夠以下調用
Class<?> tabLayoutClass = TabLayout.class;

//而對於基本數據類型咱們可使用 XXX.TYPE 的方式調用
Class<?> classInt = Integer.TYPE;
複製代碼
  • **經過 Class 的靜態方法 Class.forName(String name) 方法傳入一個類的全量限定名得到建立。**該方法會要求拋出或者捕獲ClassNotFoundException異常。
Class c3 = Class.forName("android.support.design.widget.TabLayout");
複製代碼

經過反射獲取目標的類的成員變量

Class 類能夠幫助咱們在只知道一個類的名字的時候,獲取該類的成員變量,及時某些成員變量是私有的。咱們假設只知道一個類的名字,並不知道其內部構成,也就是說內部沒有 API 列表提供給咱們。Java Class 類提供了4種方法,來獲取這些成員變量。

方法名稱 返回值類型 是否包含得到繼承的屬性 是否能夠得到私有屬性
getField() Field YES NO
getDeclaredField() Field NO YES
getFields() Field[] YES NO
getDeclaredFields() Field[] NO YES
  • 測試 getField() / getDeclaredField()
Class<TopStudent> topStudentClass = TopStudent.class;
  
  //id public 屬性定義在父類 Student 中
  Field id = topStudentClass.getField("id");
  //grade public 屬性定義在 TopStudent 中
  Field grade = topStudentClass.getField("grade");
  //isReal private 屬性定義在 TopStudent 中 沒法得到私有屬性將拋出NoSuchFieldException: isReal
  Field isReal = topStudentClass.getField("isReal");

  //id public 屬性定義在父類 Student 中 沒法得到 public 父類屬性 java.lang.NoSuchFieldException: id
  Field  declaredId = topStudentClass.getDeclaredField("id");
  //grade public 屬性定義在 TopStudent 中
  Field declaredGrade = topStudentClass.getDeclaredField("grade");
  //isReal private 屬性定義在 TopStudent 中
  Field declaredIsReal = topStudentClass.getDeclaredField("isReal");
複製代碼
  • 測試 getFields() / getDeclaredFields()
Field[] fields = topStudentClass.getFields();
  Field[] declaredFields = topStudentClass.getDeclaredFields();

  //fields = [public int Reflection.TopStudent.grade, public int Reflection.Student.id]
  System.out.println("fields = " + Arrays.toString(fields));

  // grade  id
  for (Field field : fields) {
      System.out.println("" + field.getName());
  }

  //declaredFields = [private boolean Reflection.TopStudent.isReal, public int Reflection.TopStudent.grade]
  System.out.println("declaredFields = " + Arrays.toString(declaredFields));
  //isReal grade
  for (Field field : declaredFields) {
      System.out.println("" + field.getName());
  }
複製代碼

事實上咱們經過反射獲取到屬性之後,下一步多是要獲取或者修改該屬性的值,Field 類也爲咱們準備了相應的 set 和 get 方法。同時 set 方法做用於私有屬性的時候將拋出 IllegalAccessException異常。此時咱們須要經過。

同時若是咱們預先不知道該屬性的類型的時候咱們也能夠經過 getType/getGenericType 來獲取該屬性的類型,後者在屬性爲泛型表示的屬性時獲取泛型的通用符號若是不是則返回值與 getType 內容相同。

TopStudent topStudent = topStudentClass.newInstance();

  Field grade = topStudentClass.getDeclaredField("grade");
  
  grade.set(topStudent, 4);
  //Can not set int field Reflection.TopStudent.grade to java.lang.Float
 // grade.set(topStudent,4.0f);
  System.out.println("grade = " + grade.get(topStudent));

  Class<?> type = grade.getType();
  Type genericType = grade.getGenericType();
  System.out.println("type = " + type);
  System.out.println("genericType = " + genericType);
  //若是咱們知道對應的變量爲基本類型變量的某個類型可使用 setXXX 的等價方法
   grade.setInt(topStudent,4);
  //Can not set int field Reflection.TopStudent.grade to (float)4.0
  //grade.setFloat(topStudent,4);


 //再給私有屬性設置值的時候要記得設置 isAccessible 爲 true
  Field isReal = topStudentClass.getDeclaredField("isReal");
  isReal.setAccessible(true);
  // 若是不設置isReal.setAccessible(true);
  // 將會拋出 can not access a member of class Reflection.TopStudent with modifiers "private"異常
  isReal.set(topStudent, true);
  boolean isRealValue = (boolean) isReal.get(topStudent);
  System.out.println("isRealValue = " + isRealValue);

  int gradeValue = grade.getInt(topStudent);
  System.out.println("gradeValue  " + gradeValue);
複製代碼

自動裝箱致使的 IllegalArgumentException 異常

值得注意的是咱們當我反射的類某個屬性爲基本數據類型的包裝類的時候,咱們沒法使用 setXXX 直接設置該數值,將拋出java.lang.IllegalArgumentException ,使用 set(Object obj,Object val) 則能夠直接運行,緣由在於 setInt 等方法沒法爲咱們作自動裝箱的操做,然後者則能夠:

// 測試 自動拆箱裝箱
  Field code = topStudentClass.getField("code");
  //裝箱成功
  code.set(topStudent,100);
  //沒法自動裝箱 Can not set java.lang.Integer field Reflection.Student.code to (int)200
  code.setInt(topStudent,200);
  int codeVal = (int) code.get(topStudent);
  System.out.println("codeVal = " + codeVal);
複製代碼

對於 final 修飾的變量改如何修改

從代碼編寫角度來看,若是咱們將一個成員變量定義爲 final 表明咱們不但願有人能夠修改它的值,可是實際的需求誰又能考慮到這裏多呢?好在經過反射咱們也能夠修改某個 final 成員變量。固然須要注意的地方比較多。

對於 Java 基本數據類型 以及用使用 String str = "111" 賦值的成員變量,在編譯期 JVM 對其作了內聯優化,能夠簡單的理解爲編譯後就寫死在.class 文件中了,咱們並不能修改爲功 final 的成員變量。

對於非上述兩種狀況是能夠修改爲功的

//測試 set final

public class Student {
    public final int id  = 30;
    public final Integer cod  = 90;
    public static final int ID = 1000;
    ...
}

Field id = topStudentClass.getField("id");
// 若是不設置 setAccessible(true) 將拋出 IllegalAccessException
// 設置 settAccessible 將繞過檢查
id.setAccessible(true);
id.set(topStudent,100);
int idVal = (int) id.get(topStudent);
System.out.println("idVal = " + idVal);//100
System.out.println("idVal = " + topStudent.id);//30 修改失敗

Field code = topStudentClass.getField("code");
code.setAccessible(true);
code.set(topStudent,100);
int codeVal = (int) code.get(topStudent);
System.out.println("codeVal = " + codeVal);//100
System.out.println("codeVal = " + topStudent.code);//100 修改爲功


Field ID = topStudentClass.getField("ID");

//即便設置了setAccessible(true) 也會拋出 IllegalAccessException
//ID.setAccessible(true);

//經過反射將對應成員變量的 final 修飾去掉
Field modifiersField = Field.class.getDeclaredField("modifiers"); 
modifiersField.setAccessible(true);
modifiersField.setInt(ID, ID.getModifiers() & ~Modifier.FINAL); 

ID.set(topStudent,100);
int IDVal = (int) id.get(topStudent);
System.out.println("IDVal = " + IDVal);//100
System.out.println("IDVal = " + TopStudent.ID);//1000 修改失敗
複製代碼

結論,沒事不要亂改 final 萬一給後人給本身挖了個大坑埋了呢。

經過反射獲取目標類的成員方法

獲取目標類的成員方法

除了經過 Class 獲取成員變量,經過反射也能夠獲取一個類的全部成員方法。與後去成員變量同樣,獲取 成員方法也有 4 個方法:

方法名稱 返回值類型 是否包含得到父類方法 是否能夠得到私有方法
getMethod() Method YES NO
getDeclaredMethod() Method NO YES
getMethods() Method[] YES NO
getDeclaredMethods() Method[] NO YES

假設咱們設置兩個類它們以下:

public class Student {
    .....
    private String name;
    .....
    
    public String getName() {
        System.out.println("我是 Student 的  public 方法");
        return name;
    }

    private void testPrivate(){
        System.out.println("我是 Student 的 private 方法");
    }
}

public class TopStudent extends Student {
    private boolean isReal;
    public int grade;

    public boolean isReal() {
        System.out.println("我是 TopStudent 的 public 方法");
        return isReal;
    }

    private void testSelfPrivate(){
        System.out.println("我是 TopStudent 的 private 方法");
    }
}

複製代碼

咱們嘗試用 getMethods()/getDeclaredMethods() 獲取 TopStudent 類所包含的方法:

private void testGetMethod() {
   Class<TopStudent> topStudentClass = TopStudent.class;
   Method[] methods = topStudentClass.getMethods();
   Method[] declaredMethods = topStudentClass.getDeclaredMethods();

   for (Method method: methods) {
       System.out.println(method.getName());
   }

   System.out.println("---------");

   for (Method method: declaredMethods) {
       System.out.println(method.getName());
   }
}
複製代碼

從打印結果能夠看出 getMethods() 方法獲取的 method 包含全部父類和當前類的全部 Public 方法,而 getDeclaredMethods() 獲取的 method 僅包含當前類的全部方法。咦好像沒有辦法獲取父類的 private 方法的途徑,什麼? 子類根本就沒法繼承父類的私有方法好伐。

/*topStudentClass.getMethods 獲取的 method 包含全部父類和當前類的全部 Public 方法*/

public boolean Reflection.TopStudent.isReal()
public java.lang.String Reflection.Student.getName()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

/*topStudentClass.getDeclaredMethods 獲取的 method 僅包含當前類的全部方法*/

boolean Reflection.TopStudent.isReal()
private void Reflection.TopStudent.testSelfPrivate()方法*/

複製代碼

一樣咱們還能夠獲取某個類的單個方法經過 Class 提供給咱們的 getMethod 和 getDeclaredMethod 這兩個方法都帶有兩個參數,第一個參數爲方法名 "name",第二個參數爲對應方法須要 傳入的參數的Class 對象 即 "Class<?>... parameterTypes"。當咱們嘗試獲取一個並不存在的方法時,將會拋出NoSuchMethodException 異常。

咱們爲 TopStudent 添加兩個方法用於測試

public void testParams(String p1,int p2){}

public void testParams(double p){}
複製代碼
try {
       // getMethod 能夠正常獲取本身以及父類的公有方法
       Method isRealMethod = topStudentClass.getMethod("isReal");
       Method getNameMethod = topStudentClass.getMethod("getName");

       // 嘗試獲取私有方法將拋出 java.lang.NoSuchMethodException 異常
       Method testSelfPrivateMethod = topStudentClass.getMethod("testSelfPrivate");
       Method testPrivateMethod = topStudentClass.getMethod("testPrivate");


       //嘗試獲取父類的方法 將拋出 NoSuchMethodException 異常
       Method getNameDeclareMethod = topStudentClass.getDeclaredMethod("getName");

       // getDeclaredMethod 能夠獲取私有方法將拋出 以及公有方法
       Method isRealDeclareMethod = topStudentClass.getDeclaredMethod("isReal");
       Method testSelfPrivateDeclareMethod = topStudentClass.getDeclaredMethod("testSelfPrivate");
        
        //重載方法的測試
        Method testParams1 = topStudentClass.getMethod("testParams", double.class);
       Method testParams2 = topStudentClass.getMethod("testParams", String.class, int.class);
       //獲取並不存在的重載方法 將拋出 java.lang.NoSuchMethodException
       Method testParams3 = topStudentClass.getMethod("testParams");

   } catch (NoSuchMethodException e) {
       e.printStackTrace();
   }
複製代碼

調用目標類的成員方法

因爲咱們上文說過了 getMethod 和 getDeclaredMethod 方法的區別了,爲了咱們正常獲取對應的方法去掉用,咱們須要使用對應的方法。

咱們獲取到了指定了 Class 的成員方法後能夠經過 Method 的

Object invoke(Object obj, Object... args)

方法來調用指定類的對象的方法。第一個參數爲該類的對象,第二個可變參數爲該方法的參數,而返回值即所調用的方法的返回值,一般須要咱們強轉爲指定參數類型。而咱們還能夠經過 Method 的 getReturnType 方法來獲取返回值類型。

另外還須要注意的是,私有成員方法和私有變量同樣,獲取能夠,可是當咱們須要訪問修改的時候,必需要繞過權限檢查即設置:method.setAccessible(true)

下面咱們來一個例子:

//爲 TopStudent 添加 testParams 測重載方法
public String testParams(int p) {
   System.out.println("我是 TopStudent 的 testParams(int p) 方法 ," + " p = " + p);
   return String.valueOf(p * 100);
}

try {
       Class<TopStudent> topStudentClass = TopStudent.class;
       TopStudent topStudent = topStudentClass.newInstance();
       
       //調用 public 方法
       Method isRealDeclareMethod = topStudentClass.getDeclaredMethod("isReal");
       isRealDeclareMethod.invoke(topStudent);

       //調用私有方法必須繞過權限檢查 即須要設置對應的 Method 對象的 setAccessible 屬性爲 true
       Method testSelfPrivateDeclareMethod = topStudentClass.getDeclaredMethod("testSelfPrivate");
       testSelfPrivateDeclareMethod.setAccessible(true);
       testSelfPrivateDeclareMethod.invoke(topStudent);
       
       Method testParams1 = topStudentClass.getMethod("testParams", double.class);

       //傳入錯誤的參數類型將會拋出 IllegalArgumentException 異常
       //testParams1.invoke(topStudent,"200");
       testParams1.invoke(topStudent, 200);

       Method testParams2 = topStudentClass.getMethod("testParams", String.class, int.class);
       testParams2.invoke(topStudent, "測試", 200);

       Method testParams3 = topStudentClass.getMethod("testParams", int.class);
       Class<?> returnType = testParams3.getReturnType();
        //returnType = class java.lang.String
       System.out.println("returnType = " + returnType);
       String result = (String) testParams3.invoke(topStudent, 200);//result = 20000

       System.out.println("result = " + result);
       
  } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
       e.printStackTrace();
   }
複製代碼

經過反射獲取目標類的構造函數

經過反射獲取構造函數的方法一樣有4個,分別爲

方法名稱 返回值類型 是否能夠得到私有方法
getConstructor() Constructor<?> NO
getDeclaredConstructor() Constructor<?> YES
getConstructors() Constructor<?>[] NO
getDeclaredConstructors() Constructor<?>[] YES

對於構造方法的獲取這裏沒有指出是否能夠得到父類的構造方法,由於 java 規定,子類沒法繼承父類的構造方法。而對於訪問修飾符的限制,這裏跟上文的普通成員函數沒有什麼區別。

如:

Class<TopStudent> topStudentClass = TopStudent.class;

   Constructor<?>[] constructors = topStudentClass.getConstructors();
   for (Constructor constructor: constructors) {
       System.out.println("constructor = " + constructor);
   }

   Constructor<?>[] declaredConstructors = topStudentClass.getDeclaredConstructors();
   for (Constructor constructor: declaredConstructors) {
       System.out.println("constructor = " + constructor);
   }
   
   
   try {
       Constructor<TopStudent> isRealConstructor = topStudentClass.getConstructor(boolean.class);
       System.out.println("isRealConstructor = " + isRealConstructor);

       Constructor<TopStudent> gradeConstructor = topStudentClass.getDeclaredConstructor(int.class);
       System.out.println("gradeConstructor = " + gradeConstructor);

       TopStudent topStudent = isRealConstructor.newInstance(false);
       System.out.println("topStudent.isReal = " + topStudent.isReal()); 
    }catch (NoSuchMethodException) {
        e.printStackTrace();
    }
       
複製代碼

運行結果

constructor = public Reflection.TopStudent(boolean,int)
constructor = public Reflection.TopStudent(boolean)

constructor = public Reflection.TopStudent(boolean,int)
constructor = private Reflection.TopStudent(int)
constructor = public Reflection.TopStudent(boolean)

isRealConstructor = public Reflection.TopStudent(boolean)
gradeConstructor = private Reflection.TopStudent(int)

複製代碼

而咱們以前說過經過 Class.newInstance() 能夠建立一個類的對象,可是若是一個類並無提供空參數的構造方法,那麼這個方法將拋出 InstantiationException 異常。此時咱們就能夠經過獲取其餘參數構造函數的方法來得到對應的 Constructor 對象來調用 Constructor.newInstance(Object... obj)

此方法接受對應的構造函數的參數類型的對象,若是傳遞的參數個數以及類型錯誤將拋出IllegalArgumentException,相似於 invoke 方法所拋出的異常。

try {

        // 若是沒有空構造函數,將拋出 InstantiationException 異常
        //  TopStudent topStudent = topStudentClass.newInstance();
       TopStudent topStudent = isRealConstructor.newInstance(false);
       System.out.println("topStudent.isReal = " + topStudent.isReal());

       //調用私有構造函數的時候必須把對應的 Constructor 設置爲  setAccessible(true)
       gradeConstructor.setAccessible(true);
       TopStudent topStudent1 = gradeConstructor.newInstance(1000);
       System.out.println("topStudent.grade = " + topStudent1.grade);
       //傳入錯誤的參數的個數的時候將會拋出 java.lang.IllegalArgumentException
       TopStudent errorInstance = isRealConstructor.newInstance(false, 100);


   } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
       e.printStackTrace();
   }
複製代碼

經過 Class 作類型判斷

在不使用反射的時候,咱們會用 instanceof 關鍵字來判斷是否爲某個類的實例。當咱們經過上面的方法獲取了一個對象的 Class 對象,也能夠Class對象的 isInstance() 方法來判斷是否爲某個類的實例,它是一個 Native方法,使用方法以下:

try {
       Class<Student> studentClass = Student.class;
       //java 中內部類的全路徑命名是 OuterClassName$InnerClassName
       Class<?> tearcherClass = Class.forName("ReflectionTest$Teacher");

       Teacher teacher = new Teacher();
       //tearcherClass.isInstance(teacher) true 
       System.out.println("tearcherClass.isInstance(teacher)" + tearcherClass.isInstance(teacher));
   } catch (ClassNotFoundException e) {
       e.printStackTrace();
   }
複製代碼

經過反射獲取註解相關信息

開頭提到,學習反射可能更大目的不是應用於平常開發,而是爲了學習一些三方庫的源碼,而這些源碼中,反射每每都是伴隨着註解一塊使用的,這篇文章咱們暫時不拿註解展開說,只簡單的說下Annotation 相關的反射 API:

首先在 java.lang.reflect 包下有一個跟提取註解很是相關的接口,它就是 AnnotatedElement 接口,那麼實現該接口的對象有哪些呢?其實它包含了上述咱們所說的 ClassConstructor、 FieldMethod幾個類。其實瞭解註解能夠修飾哪些成員的朋友對此並不難理解,註解能夠修飾一個類,一個方法,一個成員,因此當咱們須要自定義註解的時候,若是拿到對應的成員或者類的註解即是關鍵。

AnnotatedElement 接口定義了一下幾個方法:

方法名 參數 返回值 做用
isAnnotationPresent 註解修飾的元素的 Class boolean 檢測該元素是否被參數對應註解修飾
getAnnotation 註解修飾的元素的 Class Annotation 返回註解對象
getAnnotations Annotation[] 返回該程序元素上存在的全部註解(若是沒有註解存在於此元素上,則返回長度爲零的一個數組。)
       
getDeclaredAnnotations Annotation[] 返回直接存在於此元素上的全部註解。與此接口中的其餘方法不一樣,該方法將忽略繼承的註解。(若是沒有註解直接存在於此元素上,則返回長度爲零的一個數組。)

下面咱們經過一個簡單的例子來了解下如何經過反射獲取註解:

假設咱們有一個這樣的自定義註解:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
protected @interface FruitName {
   String value();
}
複製代碼

且咱們定義了一個 Apple:

public class Apple {
   @FruitName(value = "Apple")
   public String name;
}
複製代碼

並有下列方法用來查看註解信息:

public static void getFruitInfo(Class<?> clazz) {
   try {
       String fruitName = "水果名稱:";

       Field field = clazz.getDeclaredField("name");
       java.lang.annotation.Annotation[] annotations = field.getAnnotations();
       System.out.println("annotations = " + Arrays.toString(annotations));
       if (field.isAnnotationPresent(FruitName.class)) {
           FruitName fruitNameAnno = field.getAnnotation(FruitName.class);
           fruitName = fruitName + fruitNameAnno.value();
           System.out.println(fruitName);
       }
   } catch (NoSuchFieldException e) {
       e.printStackTrace();
   }
}
複製代碼

獲得打印結果爲

annotations = [@Annotation$FruitName(value=Apple)]
水果名稱:Apple
複製代碼

總結

本文分析了一些常見的反射 API 的使用。這些並非所有的 API。網上也有不少其餘的反射的講解也都不錯。本文出發點想要不同凡響,可是寫着寫着就"同流合污"了。 原本想說明反射中的泛型擦除,也想加上動態代理,雖然這兩個知識點和反射有着很大的聯繫,可是兩個均可獨立成文。因此僅當此篇是一份學習記錄,方便之後查閱吧。最後放出我所查看過一些不錯的反射文章。

一些不錯的反射介紹文章:

深刻解析Java反射(1) - 基礎 Java 反射由淺入深 | 進階必備 JAVA反射與註解 反射技術在android中的應用 細說反射,Java 和 Android 開發者必須跨越的坎 Thinking in JavaJava 核心技術卷 I

相關文章
相關標籤/搜索