透過反射從 Java 欄位取得字串值
1. 簡介
在本教程中,我們將學習如何使用反射從 Java 欄位取得String
值。 Java 中的反射是一個強大的功能,它允許我們在運行時檢查並與類別、字段、方法和建構函數進行交互,即使我們在編寫程式碼時並不了解所有細節。
2. 存取公共字段
最簡單的場景是讀取公共String
欄位的值。存取公共欄位無需繞過 Java 的常規存取規則,這使得反射過程變得簡單:
public class PublicFieldDemo {
public String name = "Baeldung";
}
@Test
void givenPublicStringField_whenAccessWithReflection_thenReturnValue() throws Exception {
PublicFieldDemo example = new PublicFieldDemo();
Field field = PublicFieldDemo.class.getField("name");
String value = (String) field.get(example);
assertEquals("Baeldung", value);
}
在此範例中, getField(“name”)
在給定類別及其超類別中搜尋名為「 name
」的公共欄位。如果找到,我們可以呼叫get(example)
從實例中檢索其值。
由於 get 方法傳回一個對象,因此我們在測試中進行比較之前將其轉換為String
。
3.訪問私有字段
在大多數應用程式中,欄位都是私有的,以遵循封裝原則。反射仍然可以存取這些字段,但我們必須明確覆蓋 Java 的常規存取檢查:
public class PrivateFieldDemo {
private String secret = "Hidden Value";
}
@Test
void givenPrivateStringField_whenAccessWithReflection_thenReturnValue() throws Exception {
PrivateFieldDemo example = new PrivateFieldDemo();
Field field = PrivateFieldDemo.class.getDeclaredField("secret");
field.setAccessible(true);
String value = (String) field.get(example);
assertEquals("Hidden Value", value);
}
在此範例中,我們使用getDeclaredField(“secret”)
而不是getField()
。此方法會在類別本身中尋找字段,無論該字段是公共的、受保護的還是私有的,但它不會搜尋父類別。由於該欄位是私有的,因此在不改變其可訪問性的情況下嘗試存取它將導致IllegalAccessException
。
透過呼叫setAccessible(true)
,我們暫時禁用了 Java 對此欄位的存取控制檢查,從而允許我們讀取其值。這種技術功能強大,但應謹慎使用,因為它會破壞封裝性。
4. 讀取具有動態名稱的字段
有時,欄位名稱在編譯時未知,而是在程式執行期間確定。這在使用動態資料來源時很常見,例如從設定檔讀取字段名稱、將 JSON 鍵映射到物件字段,或適應資料庫架構變更。
反射允許我們將欄位名稱儲存在變數中並仍然可以存取相應的值:
public class DynamicFieldDemo {
public String title = "Dynamic Access";
}
@Test
void givenFieldNameVariable_whenAccessWithReflection_thenReturnValue() throws Exception {
DynamicFieldDemo example = new DynamicFieldDemo();
String fieldName = "title";
Field field = DynamicFieldDemo.class.getField(fieldName);
String value = (String) field.get(example);
assertEquals("Dynamic Access", value);
}
這裡的過程與存取公共欄位相同,只是我們傳遞的不是硬編碼的字串,而是包含欄位名稱的變數。這種方法對於必須處理多個物件和欄位而無需對每個名稱進行硬編碼的通用實用程式非常有用。
它允許程式碼在運行時進行調整,使其更加靈活和可重複使用。
5. 通用實用方法
為了避免在多個地方重複反射邏輯,我們可以將其包裝成一個可重複使用的方法。此方法適用於公有和私有字段,處理任何類型,並允許我們安全地取得String
值,而不必擔心null
或類型不符:
public class User {
private String username = "baeldung_user";
}
public static String getFieldValueAsString(Object obj, String fieldName) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
boolean accessible = field.canAccess(obj);
try {
if (!accessible) {
field.setAccessible(true);
}
return Objects.toString(field.get(obj), null);
} finally {
if (!accessible) {
field.setAccessible(false);
}
}
}
@Test
void givenObjectAndFieldName_whenUseUtilityMethod_thenReturnStringValue() throws Exception {
User user = new User();
String value = getFieldValueAsString(user, "username");
assertEquals("baeldung_user", value);
}
在這個實用方法中,我們使用Objects.toString(field.get(obj), null)
將值安全地轉換為String
,如果欄位為null
則傳回null
。
6. 結論
在本文中,我們探討了使用反射從 Java 欄位檢索String
值的各種方法。反射提供了靈活性,但應謹慎使用,因為它可以繞過封裝,並且與直接存取欄位相比會降低效能。
與往常一樣,原始碼可 在 GitHub 上取得。