Java 反射
一、Java 語言的反射機制
在Java執行時環境中,對於任意一個類,能否知道這個類有哪些屬性和方法?對於任意一個物件,能否呼叫它的任意一個方法?
答案是肯定的。這種動態獲取類的資訊以及動態呼叫物件的方法的功能來自於Java 語言的反射(Reflection)機制。
Java 反射機制主要提供了以下功能:
- 在執行時判斷任意一個物件所屬的類。
- 在執行時構造任意一個類的物件。
- 在執行時判斷任意一個類所具有的成員變數和方法。
- 在執行時呼叫任意一個物件的方法
Reflection 允許程式在執行時透過Reflection APIs取得任何一個 已知名稱的class的內部資訊,包括其modifiers(諸如public, static 等等)、superclass(例如Object)、實現之interfaces(例如Serializable),也包括fields和methods的所有資訊,並可於執行時改變fields內容或呼叫methods。
那麼反射這麼厲害,java是不是動態語言呢?
來看一下動態語言百科上的定義:
動態語言,是指程式在執行時可以改變其結構:新的函式可以被引進,已有的函式可以被刪除等在結構上的變化。
從這個角度看很明顯,發現java不是動態語言
儘管在這樣的定義與分類下Java不是動態語言,它卻有著一個非常突出的動態相關機制:Reflection。這個字的意思是“反射、映象、倒影”,用在Java身上指的是我們可以於執行時載入、探知、使用編譯期間完全未知的classes。換句話說,Java程式可以載入一個執行時才得知名稱的class,獲悉其完整構造(但不包括methods定義),並生成其物件實體、或對其fields設值、或呼叫其methods。
二、Java Reflection API 簡介
在JDK中,主要由以下類來實現Java反射機制,這些類都位於java.lang.reflect包中
- Class類:代表一個類。
- Field 類:代表類的成員變數(成員變數也稱為類的屬性)。
- Method類:代表類的方法。
- Constructor 類:代表類的構造方法。
- Array類:提供了動態建立陣列,以及訪問陣列的元素的靜態方法
具體如下:
常用方法用法:
1、獲得物件的型別
Class classType=object.getClass();
在java.lang.Object 類中定義了getClass()方法,因此對於任意一個Java物件,都可以通過此方法獲得物件的型別。Class類是Reflection API 中的核心類,它有以下方法:
- getName():獲得類的完整名字。
- getFields():獲得類的public型別的屬性。
- getDeclaredFields():獲得類的所有屬性。
- getMethods():獲得類的public型別的方法。
- getDeclaredMethods():獲得類的所有方法。
getMethod(String name, Class[] parameterTypes):獲得類的特定方法,name引數指定方法的名字,parameterTypes 引數指定方法的引數型別。
getConstructors():獲得類的public型別的構造方法。
getConstructor(Class[] parameterTypes):
獲得類的特定構造方法,parameterTypes 引數指定構造方法的引數型別。
newInstance():通過類的不帶引數的構造方法建立這個類的一個物件。
2、通過預設構造方法建立一個新物件
Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
以上程式碼先呼叫Class類的getConstructor()方法獲得一個Constructor 物件,它代表預設的構造方法,然後呼叫Constructor物件的newInstance()方法構造一個例項。
3、獲得物件的所有屬性
Field fields[]=classType.getDeclaredFields();
Class 類的getDeclaredFields()方法返回類的所有屬性,包括public、protected、預設和private訪問級別的屬性。
獲得每個屬性相應的getXXX()和setXXX()方法,然後執行這些方法,把原來物件的屬性拷貝到新的物件中
4、動態建立和訪問陣列
java.lang.Array 類提供了動態建立和訪問陣列元素的各種靜態方法。
三、Class
眾所周知Java有個Object class,是所有Java classes的繼承根源,其內宣告瞭數個應該在所有Java class中被改寫的methods:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一個Class object。
Class class十分特殊。它和一般classes一樣繼承自Object,其實體用以表達Java程式執行時的classes和interfaces,也用來表達enum、array、primitive Java types
(boolean, byte, char, short, int, long, float, double)以及關鍵詞void。當一個class被載入,或當載入器(class loader)的defineClass()被JVM呼叫,JVM 便自動產生一個Class object。
如果您想借由“修改Java標準庫原始碼”來觀察Class object的實際生成時機(例如在Class的constructor內新增一個println()),不能夠!因為Class並沒有public constructor。
Class是Reflection起源。針對任何您想探勘的class,唯有先為它產生一個Class object,接下來才能經由後者喚起眾多的Reflection APIs。
1、“Class” object的取得途徑。
Java允許我們從多種途徑為一個class生成對應的Class object
四、應用
程式碼操作的實體類:
1、建構函式無參
/**
* Created by jiankunking on 2016/9/16.
*/
public class entityClassWithoutParameter
{
public int getAddResult(int a, int b)
{
return a + b;
}
private int getMultiplyResult(int a, int b)
{
return a * b;
}
public String getField1()
{
return field1;
}
public void setField1(String field1)
{
this.field1 = field1;
}
public String getField2()
{
return field2;
}
public void setField2(String field2)
{
this.field2 = field2;
}
public String field1;
protected String field2;
private String field3 = "我是私有的";
/**
* 測試私有函式是否可見
* @return
*/
private String testPrivate(String string)
{
System.out.println("testPrivate:"+string);
return string;
}
}
2、建構函式有參
/**
* Created by jiankunking on 2016/9/16.
*/
public class entityClassWithParameter
{
public entityClassWithParameter(String string, int num)
{
System.out.println("我是entityClassWithParameter:" + string + num);
}
}
1、執行時生成instances
在Reflection 動態機制中有兩種作法:一個針對“無參ctor”,一個針對“帶引數ctor”。如果欲呼叫的是“帶引數ctor“就比較麻煩些,不再呼叫Class的newInstance(),而是呼叫Constructor 的newInstance()。
無參:
//獲取 指定類
Class classType = Class.forName("entityClassWithoutParameter");
//建立 無參 物件
Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
有參:
//建立 有參 物件
Class cls = Class.forName("entityClassWithParameter");
Class[] paramTypes = {String.class, int.class};
// 方法傳入的引數
Object[] params = {"我是string引數", 23};
Constructor con = cls.getConstructor(paramTypes);
//主要就是這句了
entityClassWithParameter base = (entityClassWithParameter) con.newInstance(params);
2、執行時呼叫methods
首先準備一個Class[]做為引數型別(本例指定其中一個是String,另一個是int),然後以此為自變數呼叫getMethod(),獲得特定的Method object。接下來準備一個Object[]放置引數變數,然後呼叫上述所得之特定Method object的invoke()。
//獲取 指定類
Class classType = Class.forName("entityClassWithoutParameter");
//獲取 指定方法
Method addMethod = classType.getMethod("getAddResult", new Class[]{int.class, int.class});
//呼叫函式 並接收結果
Object result = addMethod.invoke(classType.newInstance(), new Object[]{new Integer(100), new Integer(200)});
為什麼獲得Method object時不需指定回返型別?
因為method overloading機制要求signature必須唯一,而回返型別並非signature的一個成份。換句話說,只要指定了method名稱和引數列,就一定指出了一個獨一無二的method。
3、執行時變更fields內容
首先呼叫Class的getField()並指定field名稱。
獲得特定的Field object之後便可直接呼叫Field的get()和set(),
//獲取private欄位
Field f = classType.getDeclaredField("field3");
//修改protected、private欄位的可見性 public欄位不需要這句
f.setAccessible(true);
//建立 無參 物件
Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
System.out.println("獲取私有欄位值:" + f.get(objectCopy));
f.set(objectCopy,"我要修改自己");
System.out.println("獲取私有欄位值:" + f.get(objectCopy));
效果如下:
4、對類的私有變數和私有方法的訪問
//獲取private欄位
Field f = classType.getDeclaredField("field3");
//修改protected、private欄位的可見性 public欄位不需要這句
f.setAccessible(true);
//建立 無參 物件
Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
System.out.println("獲取私有欄位值:" + f.get(objectCopy));
f.set(objectCopy, "我要修改自己");
System.out.println("獲取私有欄位值:" + f.get(objectCopy));
//獲得私有方法
Method method = classType.getDeclaredMethod("testPrivate", new Class[]{String.class});
//設定私有方法可以被訪問
method.setAccessible(true);
//呼叫私有方法
String str = (String) method.invoke(objectCopy, new Object[]{"測試私有方法是否可以通過反射呼叫"});
System.out.println("我是私有方法返回值:"+str);//輸出 測試私有方法是否可以通過反射呼叫
完整測試程式碼
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Created by jiankunking on 2016/7/31.
*/
public class test
{
public static void main(final String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException
{
//獲取 指定類
Class classType = Class.forName("entityClassWithoutParameter");
//獲取 指定方法
Method addMethod = classType.getMethod("getAddResult", new Class[]{int.class, int.class});
//呼叫函式 並接收結果
Object result = addMethod.invoke(classType.newInstance(), new Object[]{new Integer(100), new Integer(200)});
//輸出 結果
System.out.println("加法結果:" + (Integer) result);
//獲取 所有方法
for (Method item : classType.getDeclaredMethods())
{
System.out.println("函式名:" + item.getName());
}
//獲取 所有public欄位
for (Field item : classType.getFields())
{
System.out.println("欄位名:" + item.getName());
}
//獲取private欄位
Field f = classType.getDeclaredField("field3");
//修改protected、private欄位的可見性 public欄位不需要這句
f.setAccessible(true);
//建立 無參 物件
Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
System.out.println("獲取私有欄位值:" + f.get(objectCopy));
f.set(objectCopy, "我要修改自己");
System.out.println("獲取私有欄位值:" + f.get(objectCopy));
//獲得私有方法
Method method = classType.getDeclaredMethod("testPrivate", new Class[]{String.class});
//設定私有方法可以被訪問
method.setAccessible(true);
//呼叫私有方法
String str = (String) method.invoke(objectCopy, new Object[]{"測試私有方法是否可以通過反射呼叫"});
System.out.println("我是私有方法返回值:"+str);//輸出 測試私有方法是否可以通過反射呼叫
//建立 有參 物件
Class cls = Class.forName("entityClassWithParameter");
Class[] paramTypes = {String.class, int.class};
// 方法傳入的引數
Object[] params = {"我是string引數", 23};
Constructor con = cls.getConstructor(paramTypes);
//主要就是這句了
entityClassWithParameter base = (entityClassWithParameter) con.newInstance(params);
}
}
結果如下:
本文部分參考百度百科及網路資料:JAVA反射機制
演示demo下載:
http://download.csdn.net/detail/xunzaosiyecao/9631373
作者:jiankunking 出處:http://blog.csdn.net/jiankunking
相關文章
- 【Java 反射學習】Java 反射基礎Java反射
- [Java 反射學習] Java 反射基礎Java反射
- Java——反射Java反射
- Java反射Java反射
- Java反射—初探反射基礎Java反射
- Java 反射 APIJava反射API
- Java 反射原理Java反射
- Java的反射Java反射
- 20201209——java反射Java反射
- 淺析Java反射--JavaJava反射
- 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 方法的反射Java反射
- Java反射機制Java反射
- JAVA反射舉例Java反射
- [Java基礎]反射Java反射
- Java學習_反射Java反射
- Java基礎 —— 反射Java反射
- 【Java面試指北】反射(1) 初識反射Java面試反射
- 【Java反射】Java 泛型基礎Java反射泛型
- Java反射與hook混用反射某支付的方法Java反射Hook
- java反射構建物件和方法的反射呼叫Java反射物件
- java反射學習(一)Java反射
- java利器——反射機制Java反射
- java 反射簡單使用Java反射