本文详解如何正确使用 Gson 库将 JSON 数组反序列化回封装了 ArrayList 的自定义容器类(如 FencersList),避免 Expected BEGIN_OBJECT but was BEGIN_ARRAY 错误,并提供完整可运行的代码示例与关键注意事项。
本文详解如何正确使用 gson 库将 json 数组反序列化回封装了 `arraylist` 的自定义容器类(如 `fencerslist`),避免 `expected begin_object but was begin_array` 错误,并提供完整可运行的代码示例与关键注意事项。
在使用 Gson 进行 JSON 序列化/反序列化时,序列化与反序列化的类型必须严格对称——这是解决本问题的核心原则。你当前的代码中,写入 JSON 时调用的是 gson.toJson(list.getCollection()),即只序列化了 ArrayList
✅ 正确做法:统一以 FencersList 为序列化/反序列化单元
首先,确保 Fencers 类具备无参构造函数和标准 getter/setter(Gson 反序列化要求):
public class Fencers {
private String name;
private String nation;
private int id;
// 必须添加无参构造函数
public Fencers() {}
public Fencers(String name, String nation, int id) {
this.name = name;
this.nation = nation;
this.id = id;
}
// 建议补充 getter 方法(Gson 读取私有字段需开启字段可见性或提供 getter)
public String getName() { return name; }
public String getNation() { return nation; }
public int getId() { return id; }
}
其次,修正 FencersList 类:添加 setCollection() 方法,并让 toString() 正确返回字符串(当前实现中混用了 System.out.println,破坏了 toString 合约):
import java.util.ArrayList;
public class FencersList {
private ArrayList<fencers> collection;
public FencersList() {
this.collection = new ArrayList();
}
public ArrayList<fencers> getCollection() {
return collection;
}
public void setCollection(ArrayList<fencers> collection) {
this.collection = collection;
}
public void addfencer(Fencers fencer) {
collection.add(fencer);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("**************** FENCERS ****************\n");
for (Fencers f : collection) {
sb.append("Name: ").append(f.getName())
.append(", Nation: ").append(f.getNation())
.append(", ID: ").append(f.getId()).append("\n");
}
return sb.toString();
}
public void printFencers() {
System.out.println(this);
}
}</fencers></fencers></fencers>
最后,在 Main 中统一使用 FencersList 类型进行序列化与反序列化:
import com.google.gson.Gson;
import java.io.*;
class Main {
public static void main(String[] args) {
// 构建初始数据
Fencers fencer1 = new Fencers("m", "egy", 100);
Fencers fencer2 = new Fencers("342", "egy", 120);
FencersList list = new FencersList();
list.addfencer(fencer1);
list.addfencer(fencer2);
Gson gson = new Gson();
// ✅ 正确写入:序列化整个 FencersList 对象
try (PrintWriter out = new PrintWriter(new FileWriter("file.json"))) {
String jsonString = gson.toJson(list); // ← 关键修改:传入 list,而非 list.getCollection()
out.write(jsonString);
} catch (IOException e) {
e.printStackTrace();
}
// ✅ 正确读取:反序列化为 FencersList 类型
try (BufferedReader br = new BufferedReader(new FileReader("file.json"))) {
FencersList loadedList = gson.fromJson(br, FencersList.class); // ← 直接还原为容器类
System.out.println("Loaded FencersList:");
loadedList.printFencers();
} catch (IOException e) {
e.printStackTrace();
}
}
}
此时生成的 file.json 将形如:
{
"collection": [
{"name":"m","nation":"egy","id":100},
{"name":"342","nation":"egy","id":120}
]
}
——这是一个 JSON 对象(BEGIN_OBJECT),其 collection 字段值为数组,完全匹配 FencersList 的结构,因此 gson.fromJson(..., FencersList.class) 可成功解析。
⚠️ 注意事项总结
-
类型一致性是前提:写什么类型,就读什么类型。若写 List
,就读 List 或 T[];若写 WrapperClass,就读 WrapperClass。 - Gson 默认访问策略:它默认通过反射读取 public 字段或 getter 方法。私有字段需配合 GsonBuilder().excludeFieldsWithoutExposeAnnotation() 或添加 @Expose 注解,或直接提供 public getter。
- 无参构造函数不可少:所有被 Gson 反序列化的类都必须有无参构造器(否则抛 InstantiationException)。
- 避免 toString() 中执行 I/O:如原代码中的 System.out.println(...),这违反了 toString 的纯函数语义,易引发意外行为。
遵循以上实践,即可稳健实现「JSON ↔ 自定义容器类」的双向转换。











