Java 反射機制

Java 反射機制

什么是反射

Java 反射是Java語言的一個很重要的特征,它使得Java具體了“動態(tài)性”。

反射主要是指程序可以訪問、檢測和修改它本身狀態(tài)或行為的一種能力。在計算機科學領域,反射是一類應用,它們能夠自描述和自控制。這類應用通過某種機制來實現(xiàn)對自己行為的描述和檢測,并能根據(jù)自身行為的狀態(tài)和結果,調整或修改應用所描述行為的狀態(tài)和相關的語義。

在Java中的反射機制,被稱為Reflection。(大家看到這個單詞,第一個想法應該就是去開發(fā)文檔中搜一下了。)它允許運行中的Java程序對自身進行檢查,并能直接操作程序的內部屬性或方法。Reflection機制允許程序在正在執(zhí)行的過程中,利用Reflection APIs取得任何已知名稱的類的內部信息,包括:package、 type parameters、 superclass、 implemented interfaces、 inner classes、 outer classes、 fields、 constructors、 methods、 modifiers等,并可以在執(zhí)行的過程中,動態(tài)生成Instances、變更fields內容或喚起methods。

Java 反射機制主要提供了以下功能

  • 在運行時判斷任意一個對象所屬的類。

  • 在運行時構造任意一個類的對象。

  • 在運行時判斷任意一個類所具有的成員變量和方法。

  • 在運行時調用任意一個對象的方法。

簡單應用

  1. 通過Class類獲取成員變量、成員方法、接口、超類、構造方法等
  • 運行時復制對象

  • 用反射機制調用對象的方法

  • 動態(tài)創(chuàng)建和訪問數(shù)組

  • 運行時變更field內容

Java 反射

核心類,位于java.lang.reflect包中

  • Class類:代表一個類。

  • Field 類:代表類的成員變量(成員變量也稱為類的屬性)。

  • Method類:代表類的方法。

  • Constructor 類:代表類的構造方法。

  • Array類:提供了動態(tài)創(chuàng)建數(shù)組,以及訪問數(shù)組的元素的靜態(tài)方法。

核心 API

在 java.lang.Object 類中定義了getClass()方法,因此對于任意一個Java對象,都可以通過此方法獲得對象的類型。

獲取類的完整名字

  • public String getName() :獲得類的完整名字。

獲取構造方法

  • Constructor getConstructor(Class[] params) 根據(jù)構造函數(shù)的參數(shù),返回一個具體的具有public屬性的構造函數(shù)

  • Constructor getConstructors() 返回所有具有public屬性的構造函數(shù)數(shù)組

  • Constructor getDeclaredConstructor(Class[] params) 根據(jù)構造函數(shù)的參數(shù),返回一個具體的構造函數(shù)(不分public和非public屬性)

  • Constructor getDeclaredConstructors() 返回該類中所有的構造函數(shù)數(shù)組(不分public和非public屬性)

獲取類的成員方法

  • Method getMethod(String name, Class[] parameterTypes) 根據(jù)方法名和參數(shù),返回一個具體的具有public屬性的方法

  • Method[] getMethods() 返回所有具有public屬性的方法數(shù)組

  • Method getDeclaredMethod(String name, Class[] params) 根據(jù)方法名和參數(shù),返回一個具體的方法(不分public和非public屬性)

  • Method[] getDeclaredMethods() 返回該類中的所有的方法數(shù)組(不分public和非public屬性),不包含繼承來的方法

獲取類的成員變量(成員屬性)

  • Field getField(String name) 根據(jù)變量名,返回一個具體的具有public屬性的成員變量

  • Field[] getFields() 返回具有public屬性的成員變量的數(shù)組

  • Field getDeclaredField(String name) 根據(jù)變量名,返回一個成員變量(不分public和非public屬性)

  • Field[] getDelcaredField() 返回所有成員變量組成的數(shù)組(不分public和非public屬性)

獲取類、屬性、方法的修飾域

類Class、Method、Constructor、Field都有一個public方法int getModifiers()。該方法返回一個int類型的數(shù),表示被修飾對象( Class、 Method、 Constructor、 Field )的修飾類型的組合值。


//打印輸出方法的修飾域

int mod = methods[i].getModifiers();

System.out.print(Modifier.toString(mod) + "");

創(chuàng)建類的一個實例


// 利用newInstance()方法,獲取構造方法的實例

Object obj = cls.newInstance();

// Class的newInstance方法,僅提供默認無參的實例化方法,類似于無參的構造方法

// Constructor的newInstance方法,提供了帶參數(shù)的實例化方法,類似于含參的構造方法

Constructor ct = cls.getConstructor(null);

Object obj = ct.newInstance(null);

調用方法

  • public Object invoke(Object obj, Object... args) 調用靜態(tài)方法時,第一個參數(shù)為 null

  • public void setAccessible(boolean flag) 可以改變私有方法的權限

原理

java虛擬機有一個運行時數(shù)據(jù)區(qū),這個數(shù)據(jù)區(qū)又被分為方法區(qū),堆區(qū)和棧區(qū),我們這里需要了解的主要是方法區(qū)。方法區(qū)的主要作用是存儲被裝載的類的類型信息,當java虛擬機裝載某個類型的時候,需要類裝載器定位相應的class文件,然后將其讀入到java虛擬機中,緊接著虛擬機提取class中的類型信息,將這些信息存儲到方法區(qū)中。這些信息主要包括:

  • 這個類型的全限定名

  • 這個類型的直接超類的全限定名

  • 這個類型是類類型還是接口類型

  • 這個類型的訪問修飾符

  • 任何直接超接口的全限定名的有序列表

  • 該類型的常量池

  • 字段信息

  • 方法信息

  • 除了常量以外的所有類變量

  • 一個到class類的引用

應用

解析 Json 格式數(shù)據(jù),并利用反射創(chuàng)建對應對象

利用反射調用私有方法


import java.lang.reflect.Constructor;

import java.lang.reflect.Method;

public class LoadMethodEx {

/**

* 在運行時加載指定的類,并調用指定的方法

* @param cName            Java的類名

* @param MethodName    方法名

* @param params        方法的參數(shù)值

* @return

*/

public Object Load(String cName, String MethodName, Object[] params) {

Object retObject = null;

try {

// 加載指定的類

Class cls = Class.forName(cName);    // 獲取Class類的對象的方法之二

// 利用newInstance()方法,獲取構造方法的實例

// Class的newInstance方法只提供默認無參構造實例

// Constructor的newInstance方法提供帶參的構造實例

Constructor ct = cls.getConstructor(null);

Object obj = ct.newInstance(null);

//Object obj = cls.newInstance();

// 根據(jù)方法名獲取指定方法的參數(shù)類型列表

Class paramTypes[] = this.getParamTypes(cls, MethodName);

// 獲取指定方法

Method meth = cls.getMethod(MethodName, paramTypes);

meth.setAccessible(true);

// 調用指定的方法并獲取返回值為Object類型

retObject = meth.invoke(obj, params);

} catch (Exception e) {

System.err.println(e);

}

return retObject;

}

/**

* 獲取參數(shù)類型,返回值保存在Class[]中

*/

public Class[] getParamTypes(Class cls, String mName) {

Class[] cs = null;

/*

* Note: 由于我們一般通過反射機制調用的方法,是非public方法

* 所以在此處使用了getDeclaredMethods()方法

*/

Method[] mtd = cls.getDeclaredMethods();

for (int i = 0; i < mtd.length; i++) {

if (!mtd[i].getName().equals(mName)) {    // 不是我們需要的參數(shù),則進入下一次循環(huán)

continue;

}

cs = mtd[i].getParameterTypes();

}

return cs;

}

}

參考:
http://www.cnblogs.com/crazypebble/archive/2011/04/13/2014582.html
http://lavasoft.blog.51cto.com/62575/43218

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容