用Java調用私有方法

1.概述

雖然在Java中將方法private ,以防止從擁有類的外部調用它們,但出於某些原因,我們可能仍需要調用它們。

為此,我們需要解決Java的訪問控制問題。這可以幫助我們到達庫的某個角落,或者允許我們測試一些通常應保密的代碼。

在這個簡短的教程中,我們將研究如何驗證方法的功能,而不考慮其可見性。我們將考慮兩種不同的方法:Java Reflection API和Spring的ReflectionTestUtils

2.可見性超出我們的控制

對於我們的示例,讓我們使用對long數組進行LongArrayUtil我們的類有兩個indexOf方法:

public static int indexOf(long[] array, long target) {

 return indexOf(array, target, 0, array.length);

 }



 private static int indexOf(long[] array, long target, int start, int end) {

 for (int i = start; i < end; i++) {

 if (array[i] == target) {

 return i;

 }

 }

 return -1;

 }

假設這些方法的可見性無法更改,但是我們要調用私有indexOf方法。

3. Java反射API

3.1。用反思找到方法

雖然編譯器阻止我們調用類中不可見的函數,但我們可以通過反射來調用函數。首先,我們需要訪問描述我們要調用的函數Method

Method indexOfMethod = LongArrayUtil.class.getDeclaredMethod(

  "indexOf", long[].class, long.class, int.class, int.class);

我們必須使用getDeclaredMethod才能訪問非私有方法。我們在具有函數的類型(在本例中為LongArrayUtil上調用它,並傳入參數的類型以標識正確的方法。

如果該方法不存在,則該函數可能會失敗並引發異常。

3.2。允許訪問方法

現在,我們需要暫時提高方法的可見性:

indexOfMethod.setAccessible(true);

此更改將持續到JVM停止或accessible屬性設置回false.

3.3。反射調用方法

最後,我們Method對像上invoke

int value = (int) indexOfMethod.invoke(

 LongArrayUtil.class, someLongArray, 2L, 0, someLongArray.length);

現在,我們已經成功訪問了私有方法。

invoke的第一個參數是目標對象,其餘參數需要匹配我們方法的簽名。在這種情況下,我們的方法是static ,目標對LongArrayUtil父類– LongArrayUtil。對於調用實例方法,我們將傳遞要調用其方法的對象。

我們還應注意, invoke返回Object ,對於void函數,該參數為null ,並且需要轉換為正確的類型才能使用它。

4. Spring ReflectionTestUtils

到達類的內部是測試中的常見問題。 Spring的測試庫提供了一些捷徑,以幫助單元測試達到類。這通常可以解決特定於單元測試的問題,在單元測試中,測試需要訪問一個私有字段,Spring可能會在運行時實例化該私有字段。

首先,我們需要在pom.xml中spring-test

<dependency>

 <groupId>org.springframework</groupId>

 <artifactId>spring-test</artifactId>

 <version>5.3.4</version>

 <scope>test</scope>

 </dependency>

現在,我們可以在ReflectionTestUtils invokeMethod函數,該函數使用與上述相同的算法,從而節省了編寫大量代碼的時間:

int value = ReflectionTestUtils.invokeMethod(

 LongArrayUtil.class, "indexOf", someLongArray, 1L, 1, someLongArray.length);

由於這是一個測試庫,因此我們不希望在測試代碼之外使用它。

5.注意事項

使用反射繞過功能可見性會帶來一些風險,甚至可能無法實現。我們應該考慮:

  • Java安全管理器是否將在我們的運行時中允許
  • 在沒有編譯時檢查的情況下,我們正在調用的函數在將來是否會繼續存在
  • 重構我們自己的代碼,使事物更清晰可見

六,結論

在本文中,我們研究瞭如何使用Java Reflection API和Spring的ReflectionTestUtils訪問私有方法。