從Java反射機制到Android註解框架
一、Java反射機制
1、定義
JAVA反射機制是在“執行狀態”中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。Java反射機制主要提供了幾個功能:在執行時判斷任意一個物件所屬的類、在執行時構造任意一個類的物件、在執行時判斷任意一個類所具有的成員變數和方法、在執行時呼叫任意一個物件的方法。
2、獲取Class物件
當我們編譯一個 Java 專案,所有的 Java 檔案都會被編譯成一個.class 檔案,這些 class 檔案在程式執行時會被 ClassLoader 載入到虛擬機器中。當一個類被載入以後,Java 虛擬機器就會在記憶體中自動產生一個 Class 物件。Java中,無論生成某個類的多少個物件,這些物件都會對應於同一個Class物件,這個Class物件是由JVM生成的,通過它能夠獲悉整個類的結構。我們通過 new 建構函式的形式建立物件實際上也是通過這些 Class 來建立。那麼,我們在程式碼中如何獲得Class物件呢?通常有三個方法,如下所示:
/**
* 獲取Class物件的三種方式
*/
public static Class<?> getClassObj() {
// 根據類名獲取Class物件
Class<?> clazz1 = People.class;
// 根據物件獲取Class物件
People people = new People();
Class<?> clazz2 = people.getClass();
// 根據完整類名獲取Class物件
try {
Class<?> clazz3 = Class.forName("com.yuyh.reflection.java.People");
} catch (ClassNotFoundException e) {
Log.e(TAG, e.toString());
}
Log.i(TAG, "clazz1 = " + clazz1);
return clazz1; // clazz2 clazz3
}
3、通過Class物件獲取目標類的物件
平時所熟悉的建立物件的方式就是去new一個類,執行他們的建構函式,那麼當我們拿到Class物件想去建立目標類物件,說是通過反射,實際上還是去執行類的建構函式。如下所示:
/**
* 反射獲取類的物件
*
* @return
*/
public static Object getObject() {
try {
// 獲取類的Class物件
Class<?> clz = getClassObj();
// 獲取類物件的Constructor
Constructor<?> constructor = clz.getConstructor(String.class, int.class, String.class);
// 在使用時取消 Java語言訪問檢查,提升反射效能
constructor.setAccessible(true);
// 通過 Constructor 來建立物件
Object obj = constructor.newInstance("yuyh", 25, "xxx@gmail.com");
Log.i(TAG, obj.toString());
return obj;
} catch (Exception e) {
Log.e(TAG, e.toString());
}
return null;
}
4、通過Class物件獲取類的所有方法
同樣,拿到Class物件之後我們可以通過呼叫getDeclaredMethods或getMethods(包括從父類繼承下來的方法) 去獲取類的所有方法,也可呼叫getDeclaredMethod (String name, Class...<?> parameterTypes) 來根據方法名獲取某個方法。如下所示:
/**
* 反射獲取類的方法
*/
public static void getDeclaredMethods() {
People people = (People) getObject();
// 獲取到類中的所有方法(不包含從父類繼承的方法)
Method[] methods = people.getClass().getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Log.i(TAG, "method[" + i + "] = " + methods[i].getName());
}
try {
// 獲取類中的某個方法
Method method = people.getClass().getDeclaredMethod("setEMail", String.class);
// 判斷是否是public方法
Log.i(TAG, "method is public = " + Modifier.isProtected(method.getModifiers()));
// 獲取該方法的引數型別列表
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
Log.i(TAG, "paramTypes[" + i + "] = " + paramTypes[i].getName());
}
Log.i(TAG, "people.email befor= " + people.getEMail());
// 執行該方法
method.invoke(people, "xxx@163.com");
Log.i(TAG, "people.email after= " + people.getEMail());
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
5、通過Class物件獲取類的所有屬性
同理,可通過getDeclaredFields、 getFields、 getDeclaredField (String name)、 getField (String name) 來獲取類的所有屬性或單個屬性。如下所示:
/**
* 反射獲取類的屬性
*/
public static void getDeclaredFields() {
People people = (People) getObject();
// 獲取當前類所有屬性
Field[] fields = people.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Log.i(TAG, "fields[" + i + "] = " + fields[i].getName());
}
try {
// 獲取當前類的某個屬性
Field field = people.getClass().getDeclaredField("name");
// 獲取屬性值
Log.i(TAG, "people.name before = " + field.get(people));
// 設定屬性值
field.set(people, "yuyh1");
Log.i(TAG, "people.name after = " + field.get(people));
} catch (Exception e) {
e.printStackTrace();
}
}
6、根據Class物件獲取父類或實現的介面
如下所示:
/**
* 獲取物件的父類
*/
public static void getSuperClass() {
Student student = new Student("142315079");
Class<?> superClass = student.getClass().getSuperclass();
while (superClass != null) {
Log.i(TAG, "superClass = " + superClass.getName());
superClass = superClass.getSuperclass(); // 迴圈獲取上一層父類(如果存在),至少存在一層java.lang.Object
}
}
/**
* 獲取物件實現的介面
*/
public static void getInterface() {
Student student = new Student("142315079");
// 獲取該類實現的所有介面
Class<?>[] interfaces = student.getClass().getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
Log.i(TAG, "interfaces[" + i + "] = " + interfaces[i].getName());
}
}
二、從Java反射到Android註解
俗話說,不會偷懶的程式設計師不是好程式設計師。相信初學Android的時候,大家都會被一堆findViewById()並且還要進行強轉這種簡單沒營養,又不得不寫的程式碼氣死,顯然,Android註解也在一定程度上幫助了你成為一名偷懶的程式猿。
什麼是註解?通常我們可以把它理解為一個標記,最常見的註解有:@Override,@Deprecated,@SuppressWarnings等。註解本質上也是一個類,他不是通過class和interface來定義,而是通過@interface來定義一個註解。如下所示:
@Documented // 是否儲存到JavaDoc文件
@Retention(RetentionPolicy.RUNTIME) // SOURCE(原始碼時),CLASS(編譯時),RUNTIME(執行時),預設為 CLASS
@Target(ElementType.METHOD) // 用於修飾哪些程式元素,如 TYPE, METHOD, CONSTRUCTOR, FIELD, PARAMETER 等,未標註則表示可修飾所有
@Inherited // 是否可以被繼承,預設為 false
public @interface Test {
int value() default 0;
}
那麼,我們如何通過註解來免去寫findViewById(), setOnClickListener() ... ... 的麻煩呢?接下來我們就自定義一個簡單的Android註解框架。
首先,定義一個註解InjectView,如下所示:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectView {
int value() default 0;
}
那麼,我們要如何來解析這個註解呢?如下所示:
package com.yuyh.reflection.annotation;
import android.app.Activity;
import android.util.Log;
import java.lang.reflect.Field;
/**
* @author yuyh.
* @date 2016/6/13.
*/
public class Inject {
public static final String TAG = "Reflection";
public static void inject(Activity activity) {
getAnnotationInfos(activity);
}
private static void getAnnotationInfos(Activity activity) {
Class clazz = activity.getClass();
Log.i(TAG, clazz.getName());
Field[] fields = clazz.getFields();
for (Field field : fields) {
InjectView injectView = field.getAnnotation(InjectView.class);
if (injectView != null) {
int id = injectView.value();
try {
field.setAccessible(true);
field.set(activity, activity.findViewById(id));
} catch (IllegalAccessException e) {
Log.e(TAG, "IllegalAccessException = " + e.toString());
}
}
}
}
}
那麼,在Activity中就可以進行註解View了。如下所示:
public class MainActivity extends AppCompatActivity {
@InjectView(R.id.hello)
TextView tvHello;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Inject.inject(this); // 初始化註解
tvHello.setText("hahaha");
}
}
tvHello.setText()方法沒有報空指標,並且成功設定值,說明我們註解View實現成功。同理,我們還可對實現對setOnClickListener等等的註解。
/**
* 解析OnClick以及OnLongClick註解
*
* @param activity
*/
private static void injectClick(final Activity activity) {
Class clazz = activity.getClass();
Log.i(TAG, clazz.getName());
Method[] methods = clazz.getDeclaredMethods();
for (final Method method : methods) {
OnClick click = method.getAnnotation(OnClick.class);
OnLongClick longClick = method.getAnnotation(OnLongClick.class);
if (click != null && click.value() != 0) {
View view = activity.findViewById(click.value());//通過註解的值獲取View控制元件
if (view == null)
return;
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
method.invoke(activity, v);//通過反射來呼叫被註解修飾的方法,把View傳回去
} catch (InvocationTargetException e) {
Log.e(TAG, "InvocationTargetException = " + e.toString());
} catch (IllegalAccessException e) {
Log.e(TAG, "IllegalAccessException = " + e.toString());
}
}
});
}
if (longClick != null && longClick.value() != 0) {
View view = activity.findViewById(click.value());
if (view == null)
return;
view.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
try {
method.invoke(activity, v);
} catch (InvocationTargetException e) {
Log.e(TAG, "InvocationTargetException = " + e.toString());
} catch (IllegalAccessException e) {
Log.e(TAG, "IllegalAccessException = " + e.toString());
}
return true;
}
});
}
}
}
原始碼地址:https://github.com/smuyyh/ReflectionDemo
Thank you for reading~~
相關文章
- Java註解與反射機制Java反射
- Java 從入門到精通-反射機制Java反射
- Java利用spring註解做反射機制JavaSpring反射
- 【Android】註解框架(一) 基礎知識Java 反射Android框架Java反射
- 小白都能學會的Java註解與反射機制Java反射
- Java 反射機制詳解Java反射
- Java ”框架 = 註解 + 反射 + 設計模式“ 之 註解詳解Java框架反射設計模式
- Java反射機制Java反射
- Java反射-註解Java反射
- java註解,反射Java反射
- java框架基礎技術之--------反射機制Java框架反射
- JAVA中的反射機制詳解Java反射
- Java核心反射機制Java反射
- java利器——反射機制Java反射
- Java的反射機制Java反射
- Java反射機制(轉)Java反射
- Java反射機制研究Java反射
- Java反射與註解Java反射
- Java 註解和反射Java反射
- Java註解和反射Java反射
- android中反射機制Android反射
- 讀懂框架設計的靈魂—Java反射機制框架Java反射
- 基於NACOS和JAVA反射機制動態更新JAVA靜態常量非@Value註解Java反射
- Java反射機制那些事Java反射
- Java 中的 反射機制Java反射
- Java反射機制簡答Java反射
- 說說 Java 反射機制Java反射
- JAVA(五)反射機制/AnnotationJava反射
- Java 反射機制分析指南Java反射
- Java 型別資訊詳解和反射機制Java型別反射
- Java之註解與反射Java反射
- 【Android】註解框架(二) 基礎知識(Java註解)& 執行時註解框架Android框架Java
- java反射機制解決資料庫查詢結果到Model類Java反射資料庫
- Android訊息機制,從Java層到Native層剖析AndroidJava
- JAVA-註解(2)-自定義註解及反射註解Java反射
- 一文帶你瞭解Java反射機制Java反射
- Java中的類反射機制Java反射
- Java筆記-反射機制(一)Java筆記反射