1. 程式人生 > >Java通過反射呼叫一個類的私有方法

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中的反射機制正是提供更高要求的程式設計來使用的,不需要考慮基本面向物件的特徵,而是要考慮能否得到和控制程式碼中的一切,這樣反射機制程式設計才有意義。