更新時間:2020-11-26 17:49:31 來源:動力節點 瀏覽1150次
Java反射(Reflection)就是在運行 Java 程序時,可以加載、探知、使用編譯期間完全未知的類。也就是說,Java 程序可以加載一個運行時才得知類名的類,獲得類的完整構造方法,并實例化出對象,給對象屬性設定值或者調用對象的方法。Java反射可以用于判斷任意對象所屬的類,獲得Class對象,構造任意一個對象以及調用一個對象。以此為基礎,我們來講一講Java反射的基本運用。
1. 獲得Class對象
Class類的實例表示Java應用運行時的類(class and enum)或接口(interface and annotation)(每個Java類運行時都在JVM里表現為一個Class對象,可通過類名.class,類型.getClass(),Class.forName("類名")等方法獲取Class對象)。基本類型boolean,byte,char,short,int,long,float,double和關鍵字void同樣表現為Class對象。
聲明普通的Class對象,在編譯器并不會檢查Class對象的確切類型是否符合要求,如果存在錯誤只有在運行時才得以暴露出來。但是通過泛型聲明指明類型的Class對象,編譯器在編譯期將對帶泛型的類進行額外的類型檢查,確保在編譯期就能保證類型的正確性。
2.判斷是否為某個類的實例
一般地,我們用 instanceof 關鍵字來判斷是否為某個類的實例。同時我們也可以借助反射中 Class 對象的 isInstance() 方法來判斷是否為某個類的實例,它是一個 native 方法:
public native boolean isInstance(Object obj);
3.創建實例
使用Class對象的newInstance()方法來創建Class對象對應類的實例
classObj.newInstance() 只能夠調用public類型的無參構造函數,此方法是過時的。
Class<?> c = String.class;
Object str = c.newInstance();
先通過Class對象獲取指定的Constructor對象,再調用Constructor對象的newInstance()方法來創建實例。
可以根據傳入的參數,調用任意構造函數,在特定情況下,可以調用私有的構造函數,此方法是推薦使用的。
//獲取String所對應的Class對象
Class<?> c = String.class;
//獲取String類帶一個String參數的構造器
Constructor constructor = c.getConstructor(String.class);
//根據構造器創建實例
Object obj = constructor.newInstance("23333");
System.out.println(obj);
4.獲取方法
getMethods()
返回某個類的所有public方法,包括自己聲明和從父類繼承的。
getDeclaredMethods()
獲取所有本類自己的方法,不問訪問權限,不包括從父類繼承的方法
getMethod(String name, Class<?>... parameterTypes)
方法返回一個特定的方法,其中第一個參數為方法名稱,后面的參數為方法的參數對應Class的對象。
Method getDeclaredMethod(String name, Class<?>... params)
方法返回一個特定的方法,其中第一個參數為方法名稱,后面的參數為方法的參數對應Class的對象
操作私有方法
/**
* 訪問對象的私有方法
* 為簡潔代碼,在方法上拋出總的異常,實際開發別這樣
*/
private static void getPrivateMethod() throws Exception{
//1. 獲取 Class 類實例
TestClass testClass = new TestClass();
Class mClass = testClass.getClass();
//2. 獲取私有方法
//第一個參數為要獲取的私有方法的名稱
//第二個為要獲取方法的參數的類型,參數為 Class...,沒有參數就是null
//方法參數也可這么寫 :new Class[]{String.class , int.class}
Method privateMethod =
mClass.getDeclaredMethod("privateMethod", String.class, int.class);
//3. 開始操作方法
if (privateMethod != null) {
//獲取私有方法的訪問權
//只是獲取訪問權,并不是修改實際權限
privateMethod.setAccessible(true);
//使用 invoke 反射調用私有方法
//privateMethod 是獲取到的私有方法
//testClass 要操作的對象
//后面兩個參數傳實參
privateMethod.invoke(testClass, "Java Reflect ", 666);
}
}
5.獲取構造函數
Constructor[] getConstructors()
獲得類的所有公共構造函數
Constructor getConstructor(Class[] params)
獲得使用特殊的參數類型的公共構造函數,
Constructor[] getDeclaredConstructors()
獲得類的所有構造函數
Constructor getDeclaredConstructor(Class[] params)
獲得使用特定參數類型的構造函數
6. 獲取成員變量字段
Field[] getFields()
獲得類的所有公共字段
Field getField(String name)
獲得命名的公共字段
Field[] getDeclaredFields()
獲得類聲明的所有字段
Field getDeclaredField(String name)
獲得類聲明的命名的字段
修改私有變量
**
* 修改對象私有變量的值
* 為簡潔代碼,在方法上拋出總的異常
*/
private static void modifyPrivateFiled() throws Exception {
//1. 獲取 Class 類實例
TestClass testClass = new TestClass();
Class mClass = testClass.getClass();
//2. 獲取私有變量
Field privateField = mClass.getDeclaredField("MSG");
//3. 操作私有變量
if (privateField != null) {
//獲取私有變量的訪問權
privateField.setAccessible(true);
//修改私有變量,并輸出以測試
System.out.println("Before Modify:MSG = " + testClass.getMsg());
//調用 set(object , value) 修改變量的值
//privateField 是獲取到的私有變量
//testClass 要操作的對象
//"Modified" 為要修改成的值
privateField.set(testClass, "Modified");
System.out.println("After Modify:MSG = " + testClass.getMsg());
}
}
7.調用方法
當我們從類中獲取了一個方法后,我們就可以用 invoke() 方法來調用這個方法。invoke 方法的原型為:
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
下面是一個實例
public class test1 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> klass = methodClass.class;
//創建methodClass的實例
Object obj = klass.newInstance();
//獲取methodClass類的add方法
Method method = klass.getMethod("add",int.class,int.class);
//調用method對應的方法 => add(1,4)
Object result = method.invoke(obj,1,4);
System.out.println(result);
}
}
class methodClass {
public final int fuck = 3;
public int add(int a,int b) {
return a+b;
}
public int sub(int a,int b) {
return a+b;
}
}
8.利用反射創建數組
數組在Java里是比較特殊的一種類型,它可以賦值給一個Object Reference。下面我們看一看利用反射創建數組的例子:
public static void testArray() throws ClassNotFoundException {
Class<?> cls = Class.forName("java.lang.String");
Object array = Array.newInstance(cls,25);
//往數組里添加內容
Array.set(array,0,"hello");
Array.set(array,1,"Java");
Array.set(array,2,"fuck");
Array.set(array,3,"Scala");
Array.set(array,4,"Clojure");
//獲取某一項的內容
System.out.println(Array.get(array,3));
}
以上就是Java反射的基本運用,這些運用離不開Java反射的核心: JVM 在運行時才動態加載類或調用方法/訪問屬性,它不需要事先(寫代碼的時候或編譯期)知道運行對象是誰。對于Java反射的核心分析,可以觀看本站的Java基礎教程。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習