如何用泛型实现通用JSON导入方法?遇类型转换异常求助
问题原因解析
- 类型擦除导致解析失败:Java泛型在运行时会擦除类型信息,你使用
DataItems<T>.class时,实际传递给Gson的是DataItems.class,Gson无法识别T的具体类型(比如House),所以会把JSON数组中的对象默认解析成LinkedTreeMap,强转成House自然抛出ClassCastException。 - 数字类型默认解析为Double:Gson在没有明确类型约束时,会把JSON中的整数解析为Double类型,这就是int类型变成Double的原因。
- 字段不匹配:你的JSON里字段是
id,但House类里对应的字段是number,这会导致该字段无法被正确赋值。
修复方案
要让Gson正确解析泛型类型,需要通过TypeToken保留泛型的类型信息,同时修正字段匹配问题:
1. 修正House类的字段映射
要么把House类的字段名改成id,要么用@SerializedName注解做字段映射:
public class House { @SerializedName("id") // 映射JSON中的id字段到number int number; String name; }
2. 修改导入方法,传递目标类型Class
这是最可靠的方案,直接让方法接收目标类型的Class对象,构造明确的泛型类型:
private <T> List<T> importFromJSON(Class<T> clazz) { try(FileInputStream fileInputStream = context.openFileInput(fileName); InputStreamReader streamReader = new InputStreamReader(fileInputStream)){ Gson gson = new Gson(); // 构造DataItems<T>的具体类型,避免类型擦除 Type dataItemsType = TypeToken.getParameterized(DataItems.class, clazz).getType(); DataItems<T> dataItems = gson.fromJson(streamReader, dataItemsType); return dataItems.getList(); } catch (IOException ex){ ex.printStackTrace(); } return null; }
调用方式
直接传入House.class,无需强转:
List<House> houseList = importFromJSON(House.class); House house = houseList.get(0); // 直接使用,不会抛出类型转换异常
可选方案:保留DataItems参数(不推荐)
如果一定要保留原方法的参数形式,可以通过反射获取传入对象的泛型类型,但这种方式依赖传入对象的泛型信息未被擦除,可靠性较低:
private <T> List<T> importFromJSON(DataItems<T> dataItems) { try(FileInputStream fileInputStream = context.openFileInput(fileName); InputStreamReader streamReader = new InputStreamReader(fileInputStream)){ Gson gson = new Gson(); // 通过反射获取泛型参数类型 Type superType = dataItems.getClass().getGenericSuperclass(); if (superType instanceof ParameterizedType) { Type[] actualTypes = ((ParameterizedType) superType).getActualTypeArguments(); if (actualTypes.length > 0) { Type dataItemsType = TypeToken.getParameterized(DataItems.class, actualTypes[0]).getType(); dataItems = gson.fromJson(streamReader, dataItemsType); return dataItems.getList(); } } } catch (IOException ex){ ex.printStackTrace(); } return null; }
调用方式
需要传入带泛型信息的匿名内部类实例(避免类型擦除):
DataItems<House> dataItems = new DataItems<House>() {}; // 匿名内部类保留泛型信息 List<House> houseList = importFromJSON(dataItems);
内容的提问来源于stack exchange,提问作者alex
相关产品推荐
相关产品推荐

