1. 引言
本教程將深入探討如何從 JSONObject 實例中獲取值。
對於 Java 中 JSON 支持的總體介紹,請參閲 JSON-Java 的介紹。
2. <em>JSONObject</em> 結構
<em>JSONObject</em> 是一種類似於映射的數據結構。它將數據存儲為一組鍵值對。雖然鍵的類型為String,但值可以是多種類型。此外,值類型可以是原始類型或複合類型。原始類型包括String、Number和Boolean類型,或JSONObject.NULL對象。複合類型包括JSONObject和JSONArray` 類型。因此,JSON 數據可能具有任意的複雜度和嵌套結構。
由於嵌套結構中獲取值需要付出更多努力。從現在開始,讓我們參考以下一個虛構員工的 JSON 數據:
{
"name" : "Bob",
"profession" : "Software engineer",
"department" : "Research",
"age" : 40,
"family" : [
{
"wife" : {
"name" : "Alice",
"profession" : "Doctor",
"age" : 38
}
},
{
"son" : {
"name" : "Peter",
"occupation" : "Schoolboy",
"age" : 11
}
}
],
"performance" : [
{
"2020" : 4.5
},
{
"2021" : 4.8
}
]
}3. JSONObject 的 Getter 方法
首先,讓我們看看 JSONObject 類提供的 Getter API。 共有兩組方法——get() 和 opt() 方法。 這兩組方法的主要區別在於,get() 方法在找不到鍵時會拋出異常,而 opt() 方法不會拋出異常,並根據方法返回 null 或特定值。
此外,每組方法包含一個通用方法和幾個帶有類型轉換的特定方法。 通用方法返回一個 Object 實例,而特定方法返回一個已轉換的實例。 讓我們使用通用 get() 方法獲取 JSON 數據中的“family”字段。 我們假設 JSON 數據已經預先加載到 jsonObject 變量中,該變量的類型為 JSONObject:
JSONArray family = (JSONArray) jsonObject.get("family");我們也可以用更易讀的方式,通過使用針對 JSONArray 的特定獲取器來實現:
JSONArray family = jsonObject.getJSONArray("family");4. 直接獲取值
在這種方法中,我們通過獲取從目標值到中間值的每個路徑上的值來直接獲取值。 下面的代碼演示瞭如何直接獲取員工的兒子姓名:
JSONArray family = jsonObject.getJSONArray("family");
JSONObject sonObject = family.getJSONObject(1);
JSONObject sonData = sonObject.getJSONObject("son");
String sonName = sonData.getString("name");
Assertions.assertEquals(sonName, "Peter");如我們所見,直接獲取值的方法存在侷限性。首先,我們需要了解 JSON 數據結構的精確信息。其次,我們需要了解每個值的具體數據類型,以便正確使用 JSONObject 的獲取方法。
此外,在 JSON 數據結構動態時,需要在代碼中添加全面的檢查。例如,對於所有 get() 方法,都需要使用 try-catch 塊將代碼包裹起來。 此外,對於 opt() 方法,需要添加空值或特定值檢查。
5. 遞歸獲取值
與 JSON 數據中獲取值的遞歸方法相比,遞歸方法更靈活且不易出錯。在實現此方法時,我們需要考慮 JSON 數據的嵌套結構。
首先,當值的鍵類型為 JSONObject 或 JSONArray 時,我們需要將遞歸搜索向下傳遞到該值。其次,當在當前遞歸調用中找到鍵時,無論值類型為原始類型還是其他類型,都需要將其映射值添加到返回結果中。
以下方法實現了遞歸搜索:
public List<String> getValuesInObject(JSONObject jsonObject, String key) {
List<String> accumulatedValues = new ArrayList<>();
for (String currentKey : jsonObject.keySet()) {
Object value = jsonObject.get(currentKey);
if (currentKey.equals(key)) {
accumulatedValues.add(value.toString());
}
if (value instanceof JSONObject) {
accumulatedValues.addAll(getValuesInObject((JSONObject) value, key));
} else if (value instanceof JSONArray) {
accumulatedValues.addAll(getValuesInArray((JSONArray) value, key));
}
}
return accumulatedValues;
}
public List<String> getValuesInArray(JSONArray jsonArray, String key) {
List<String> accumulatedValues = new ArrayList<>();
for (Object obj : jsonArray) {
if (obj instanceof JSONArray) {
accumulatedValues.addAll(getValuesInArray((JSONArray) obj, key));
} else if (obj instanceof JSONObject) {
accumulatedValues.addAll(getValuesInObject((JSONObject) obj, key));
}
}
return accumulatedValues;
}為了簡化問題,我們提供了兩種單獨的方法:一種用於在 JSONObject 中進行遞歸搜索,另一種則在 JSONArray 實例中進行操作。 JSONObject 是一種類似於映射的數據結構,而 JSONArray 是一種類似於數組的數據結構。因此,它們的迭代方式不同。因此,將所有邏輯放在一個方法中會使代碼變得複雜,需要進行類型轉換和 if-else 分支。
最後,讓我們為 getValuesInObject() 方法編寫測試代碼:
@Test
public void getAllAssociatedValuesRecursively() {
List<String> values = jsonObjectValueGetter.getValuesInObject(jsonObject, "son");
Assertions.assertEquals(values.size(), 1);
String sonString = values.get(0);
Assertions.assertTrue(sonString.contains("Peter"));
Assertions.assertTrue(sonString.contains("Schoolboy"));
Assertions.assertTrue(sonString.contains("11"));
values = jsonObjectValueGetter.getValuesInObject(jsonObject, "name");
Assertions.assertEquals(values.size(), 3);
Assertions.assertEquals(values.get(0), "Bob");
Assertions.assertEquals(values.get(1), "Alice");
Assertions.assertEquals(values.get(2), "Peter");
}6. 結論
在本文中,我們討論瞭如何在 JSONObject 中獲取值。