【Android】註解框架(一) 基礎知識Java 反射

指間沙似流年發表於2017-12-23

目錄

  1. 【Android】註解框架(一)-- 基礎知識Java 反射
  2. 【Android】註解框架(二)-- 基礎知識(Java註解)& 執行時註解框架
  3. 【Android】註解框架(三)-- 編譯時註解,手寫ButterKnife
  4. 【Android】註解框架(四)-- 一行程式碼注入微信支付

定義

主要是指程式可以訪問,檢測和修改它本身狀態或行為的一種能力,並能根據自身行為的狀態和結果,調整或修改應用所描述行為的狀態和相關的語義。

反射機制就是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。

用一句話總結就是反射可以實現在執行時可以知道任意一個類的屬性和方法。

作用

  • 指的是可以於執行時載入,探知和使用編譯期間完全未知的類
  • 程式在執行狀態中, 可以動態載入一個只有名稱的類, 對於任意一個已經載入的類,都能夠知道這個類的所有屬性和方法; 對於任意一個物件,都能呼叫他的任意一個方法和屬性
  • 載入完類之後, 在堆記憶體中會產生一個Class型別的物件(一個類只有一個Class物件), 這個物件包含了完整的類的結構資訊,而且這個Class物件就像一面鏡子,透過這個鏡子看到類的結構

Class物件

Class是反射的基礎,是java.lang.Class的例項物件,並且Class是所有類的類型別。

private Class(ClassLoader loader) {
   // Initialize final field for classLoader.  The initialization value of non-null
   // prevents future JIT optimizations from assuming this final field is null.
   classLoader = loader;
}
複製程式碼

通過原始碼可以看到Class的建構函式是私有的,只有JVM才可以建立Class物件,我們不能通過new Class()的方式獲取到Class物件。

每個類被載入進入記憶體之後,系統就會為該類生成一個對應的java.lang.Class物件,通過該Class物件就可以訪問到JVM中的這個類.

假設有Person類,我們可以通過以下的方法來獲取到Class:

  1. 通過Person的物件,person.getClass()
  2. Person.class
  3. Class.forName(Person的全路徑包名)

獲取到了Class之後我們就能通過Java提供的API來訪問或者修改Person類的各種屬性和方法。

建立物件

我們在獲取到了Class之後可以來建立物件,最常見的做法:

Class personClazz = Class.forName(com.example.Person);
Object person = personClazz.newInstance();
複製程式碼

通過Class我們只能通過無參建構函式來建立物件。

另外我們也可以通過Class獲取到建構函式之後通過建構函式來建立物件。

獲取建構函式

//  獲得該類所有的構造器,不包括其父類的構造器
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
// 獲得該類所以public構造器,包括父類 
public Constructor<T> getConstructor(Class<?>... parameterTypes) 
複製程式碼

我們可以通過獲取建構函式之後來建立物件,舉個例子:

public class Person{
	private String name;
	
	public Person(String name){
		this.name = name;
	}
}

public class Test{
	public static void main(String[] args){
		Class clazz = Class.forName("com.example.Person");
		Constructor constructor = clazz.getDeclaredConstructor(String.class);
		constructor.newInstance("張三");
	}
}
複製程式碼

獲取方法

// 得到該類所有的方法,不包括父類的 
public Method getDeclaredMethod(String name, Class<?>... parameterTypes) 
// 得到該類所有的public方法,包括父類的
public Method getMethod(String name, Class<?>... parameterTypes)
// 得到該類所有的方法,不包括父類的或者
Method[] methods = c.getDeclaredMethods(); 
// 得到該類所有的public方法,包括父類的
Method[] methods = c.getMethods();
複製程式碼

獲取單個方法的Class<?>... parameterTypes參數列示的是想反射的方法的引數的類型別。 舉個例子:

public class Person{
	private String name;
	
	public void setName(String name){
		this.name = name;
	}
}

public class Test{
	public static void main(String[] args){
		Class clazz = Class.forName("com.example.Person");
		Object person = clazz.newInstance();
		Method method = clazz.getDeclaredMethod("setName", String.class);
		method.invoke(person, "張三");
	}
}
複製程式碼

最後通過invoke方法呼叫方法,其中第一個引數是例項物件,後面的是引數。

獲取屬性

// 獲得該類自身宣告的所有變數,不包括其父類的變數
public Field getDeclaredField(String name) 
// 獲得該類自所有的public成員變數,包括其父類變數
public Field getField(String name) 
// 返回 Field 物件的一個陣列
public Field[] getDeclaredFields()
複製程式碼

其他

// 將此物件的 accessible 標誌設定為指示的布林值。值為 true 則指示反射的物件在使用時應該取消 Java 語言訪問檢查。值為 false 則指示反射的物件應該實施 Java 語言訪問檢查。
void setAccessible(boolean flag)

// 獲取屬性或者方法或者類上的註解
<T extends Annotation> T getAnnotation(Class<T> annotationClass) 
Annotation[] getAnnotations() 
複製程式碼

其他具體方法和屬性可以參考:Java api 連結,搜尋java.lang.reflect包。

相關文章