Java 里 JSONArray 转成 List 的几种写法
接口返回一个 JSON 数组,代码里需要 List<T>,中间这步转换几乎每个项目都会写。麻烦在于项目里可能同时引了 FastJSON、Gson、Jackson 三个库,写法各不一样,抄错一行就 ClassCastException。
一、FastJSON:一行搞定
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
String json = "[{\"id\":1,\"name\":\"张三\"},{\"id\":2,\"name\":\"李四\"}]";
// 直接解析成 List
List<User> users = JSON.parseArray(json, User.class);
// 已经有 JSONArray 对象
JSONArray arr = JSON.parseArray(json);
List<User> users2 = arr.toJavaList(User.class);
toJavaList 内部会做类型转换,比 for 循环强转安全。要注意 fastjson 版本,1.2.24 之前有反序列化漏洞,建议用 fastjson2 或者最新 1.2.x。
二、Gson:需要 TypeToken
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
String json = "[{\"id\":1,\"name\":\"张三\"}]";
Type type = new TypeToken<List<User>>(){}.getType();
List<User> users = new Gson().fromJson(json, type);
TypeToken 的作用是保留泛型信息。Java 泛型在运行时会被擦除,直接写 List<User>.class 拿不到泛型,所以要用匿名子类的方式把类型"刻"在字节码里。这一步不能省,写成 new Gson().fromJson(json, List.class) 会得到 List<LinkedTreeMap>,取值时必然报错。
三、Jackson:TypeReference 同理
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper mapper = new ObjectMapper();
List<User> users = mapper.readValue(json, new TypeReference<List<User>>(){});
Jackson 对字段命名有要求,User 类里如果字段是驼峰而 JSON 是下划线,需要加 @JsonProperty 或者配置命名策略。Gson 默认按字段名精确匹配,两边规则不一样,切换库时容易出问题。
四、org.json:最原始的方式
import org.json.JSONArray;
JSONArray arr = new JSONArray(json);
List<User> users = new ArrayList<>();
for (int i = 0; i < arr.length(); i++) {
JSONObject o = arr.getJSONObject(i);
User u = new User();
u.setId(o.getInt("id"));
u.setName(o.getString("name"));
users.add(u);
}
org.json 是 Android 内置的库,不用额外依赖,但只能手动映射,字段多了很啰嗦。适合字段少又不想引入新依赖的场景。
五、Object 数组强制转换的老写法
List<Object> list = JSON.parseObject(json, List.class);
List<User> users = list.stream()
.map(o -> JSON.parseObject(JSON.toJSONString(o), User.class))
.collect(Collectors.toList());
先转 Object 再转字符串再反序列化,性能差,但兼容性好,库版本混乱时能救急。不推荐长期用。
六、踩过的坑
- 数字类型:JSON 里的 1 反序列化到 Integer 字段没问题,字段是 Long 时 FastJSON 可能报错,显式声明泛型可以避免。
- 日期格式:默认按时间戳解析,传的是 "2026-01-01 12:00:00" 会报错,要配 DateFormat 或者用 @JSONField(format=...)。
- 空数组:"[]" 转出来是空 List,不是 null;"null" 转出来是 null。前端判空时两种都要处理。
- 字段多余:JSON 里有但实体类没有的字段,Jackson 默认报 UnrecognizedPropertyException,加 @JsonIgnoreProperties(ignoreUnknown = true) 解决。
- 嵌套泛型:List<Map<String, List<User>>> 这种,TypeToken 要完整写出来,不能只写外层。
七、怎么选
新项目统一用 Jackson 或 fastjson2,别三个库同时引。已有项目里已经用哪个就跟着用哪个,混用会导致同名字段解析结果不一致,排查起来特别费时间。