反射獲取一個類的私有方法
今天在刷面試題的時候,發現一個題目是編寫程序通過反射獲取一個類的私有方法,因為之前學反射的時候也學的淺,沒有考慮到這樣的事情。今天敲了一下,雖然也就是那麽幾行代碼,還是磕磕絆絆的,最後終於搞定了,這裏總結一下
Java反射得到一個類的私有方法
獲得私有方法的流程是
(1)獲取目標類
(2)獲取目標方法
Method method=clazz.getDeclaredMethod(name);//可以調用類中的所有方法(不包括父類中繼承的方法)
Method method=clazz.getMethod(name);//可以調用類中有訪問權限的方法(包括父類中繼承的方法)
(3)method.toGenericString()或method.toString()方法來輸出方法的字符串形式
toGenericString()
返回描述此 Method
的字符串,包括類型參數。
toString()
返回描述此 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中的反射機制正是提供更高要求的編程來使用的,不需要考慮基本面向對象的特征,而是要考慮能否得到和控制代碼中的一切,這樣反射機制編程才有意義。
參考網站
[1]通過反射訪問任意類的私有方法和屬性
http://blog.csdn.net/a997208868/article/details/48133129
[2]Java反射機制詳解
http://www.cnblogs.com/lzq198754/p/5780331.html
[3]https://zhidao.baidu.com/question/239368481.html
反射獲取一個類的私有方法