1. 程式人生 > >反射獲取一個類的私有方法

反射獲取一個類的私有方法

st2 取消 目的 tac cat trac 屬性 一起 dao

今天在刷面試題的時候,發現一個題目是編寫程序通過反射獲取一個類的私有方法,因為之前學反射的時候也學的淺,沒有考慮到這樣的事情。今天敲了一下,雖然也就是那麽幾行代碼,還是磕磕絆絆的,最後終於搞定了,這裏總結一下

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

反射獲取一個類的私有方法