Java通過反射呼叫一個類的私有方法
本文轉載自:https://www.cnblogs.com/ghq120/p/8439204.html
獲得私有方法的流程是
(1)獲取目標類
(2)獲取目標方法
Method method=clazz.getDeclaredMethod(name);//可以呼叫類中的所有方法(不包括父類中繼承的方法)
Method method=clazz.getMethod(name);//可以呼叫類中有訪問許可權的方法(包括父類中繼承的方法)
(3)method.toGenericString()或method.toString()方法來輸出方法的字串形式
返回描述此 Method
的字串,包括型別引數。
返回描述此 Method
目前沒有弄清這兩種方法的具體區別,測試的方法中輸出的結果一樣,以後弄清區別再來更改。
(4)使用invoke()方法呼叫方法
package test0210;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class test1 {
//類的私有方法
private String testMethod(int num){
return "輸入的數字為:"+num;
}
public static void main(String[] args) {
try {
Class clazz = Class.forName("test0210.test1");
Method method = clazz.getDeclaredMethod("testMethod", int.class);
//列印完整地方法表示字串
System.out.println(method.toGenericString());
//呼叫方法
Object obj = method.invoke(clazz.newInstance(), 2);
System.out.println(obj);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
上面的程式碼將測試和私有方法放在了一起,沒有出現異常。
下面的程式碼將測試和方法分開在兩個類中,執行後會出現 java.lang.IllegalAccessException異常
package test0210;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class test2 {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("test0210.test1");
Method method = clazz.getDeclaredMethod("testMethod", int.class);
System.out.println(method.toGenericString());
Object obj = method.invoke(clazz.newInstance(), 2);
System.out.println(obj);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
查詢資料說明該異常是在反射中呼叫了private修飾的方法。咦,反射不是可以得到私有的方法,為什麼這裡不能,沒辦法繼續上網查資料。。。
最後搞明白了是缺少setAccessible(true)方法,使用繼承父類(AccessibleObject類)來的setAccessible()方法,來設定或取消訪問檢查,以達到訪問私有物件的目的。
Class<?> clazz = Class.forName("test0210.test1");
Method method = clazz.getDeclaredMethod("testMethod", int.class);
method.setAccessible(true);
System.out.println(method.toGenericString());
Java反射機制呼叫私有方法,是不是破壞了Java的封裝性?
答案是否定的。要探討這個問題,就必須要知道什麼是封裝性,什麼是安全?
封裝,是將具體的實現細節隱藏,而把功能作為整體提供給類的外部使用,也就是說,公有方法能夠完成類所具有的功能。當別人使用這個類時,如果通過反射直接呼叫私有方法,可能根本實現不了類的功能,甚至可能會出錯,因此通過反射呼叫私有方法可以說是沒有任何用處的,開發人員沒有必要故意去破壞封裝好的類。從這點上看,封裝性並沒有被破壞。
安全,如果意思是保護實現原始碼不被別人看見,那沒有作用。不用反射也能輕易獲取原始碼。
我以為反射機制只是提供了一種強大的功能,使得開發者能在封裝之外,按照特定的需要實現一些功能。
Java語言是一個嚴謹的程式語言,語言本身是靜態的。為了能讓語言具有動態程式設計的特性,必須要有反射機制。而反射機制本身就是底層的處理,不可能按表層的封轉特性來處理。也就是說不給呼叫私有方法的能力,很多程式受到侷限,那麼實現起來就麻煩了。
舉一個生活的例子,你家的電視機是要由外殼的,目的是不讓普通人接觸到電視中的電路。那麼Java語言的基本面向物件特徵正是這個層次的應用。也就是對於普通程式設計師的程式,是通過遙控器來操作電視的。但是,如果你是一個專業的電工的話,那麼可以開啟電視機的後蓋,調整電視中的電路和結構,甚至如果是電工的話,那麼調臺可能都不使用遙控器,而是通過調整內部電路的電阻的阻值來實現。Java中的反射機制正是提供更高要求的程式設計來使用的,不需要考慮基本面向物件的特徵,而是要考慮能否得到和控制程式碼中的一切,這樣反射機制程式設計才有意義。