You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gson导入导出Shape继承类列表时报无参构造调用失败如何解决

问题原因

你遇到的两个问题本质都是Gson默认不支持多态类型的序列化/反序列化导致的:

  1. 最初的Failed to invoke public Shape() with no args报错:Gson反序列化时需要先实例化目标类型的对象,而Shape是抽象类,无法直接被实例化,同时你也没有为Shape定义无参构造方法,直接触发实例化失败异常。
  2. 移除abstract修饰符后丢失子类属性:Gson默认序列化时不会保存对象的实际运行时类型信息,只会按照你声明的List<Shape>静态类型进行序列化,所有子类实例都会被向上转型为Shape结构输出,反序列化时也只会生成Shape类型的对象,自然不会带有子类的a、b等特有属性。

解决方案

使用Gson官方提供的RuntimeTypeAdapterFactory多态类型适配器解决,操作步骤如下:

1. 引入依赖

RuntimeTypeAdapterFactory属于Gson扩展包,需要额外引入依赖(以Maven为例):

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson-extras</artifactId>
    <version>和你项目中gson核心包的版本保持一致</version>
</dependency>

2. 补充无参构造方法

为Shape抽象类和所有子类添加protected级别的无参构造,供Gson实例化对象使用:

// Shape类补充
protected Shape() {}

// Rectangle类补充
protected Rectangle() {}
// Circle、Square同理补充

3. 注册多态类型适配器

在初始化Gson时注册RuntimeTypeAdapterFactory,指定基类、类型标识字段、以及所有子类对应的标识:

// 统一创建Gson实例的配置,序列化和反序列化都要用同一个配置的Gson对象
RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory = RuntimeTypeAdapterFactory
    .of(Shape.class, "shapeType") // 第二个参数为JSON中存储类型标识的字段名,序列化时自动写入
    .registerSubtype(Rectangle.class, "RECTANGLE")
    .registerSubtype(Circle.class, "CIRCLE")
    .registerSubtype(Square.class, "SQUARE");

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(shapeAdapterFactory)
    .create();

4. 调整原有导入导出方法

把原来方法中默认创建的Gson实例替换为上面配置好的实例即可:

public static List<Shape> importShapeListFromJsonWithGson(String path) throws IOException {
    Type listType = new TypeToken<List<Shape>>() {}.getType();
    // 用上面配置好的gson实例,不要用默认的new GsonBuilder().create()
    Reader reader = new FileReader(path);
    List<Shape> result = gson.fromJson(reader, listType);
    reader.close();
    return result;
}

public static void exportShapeListToJsonWithGson(List<Shape> list, String path) throws IOException {
    Writer writer = new FileWriter(path);
    // 用上面配置好的gson实例
    gson.toJson(list, writer);
    writer.close();
}

额外说明

  • 序列化生成的JSON会自动新增shapeType字段,值为你注册的子类标识,反序列化时Gson会根据这个字段自动匹配对应的子类实例化,完整保留子类所有属性。
  • 如果不希望shapeType字段保留在反序列化后的对象属性中,可以将适配器初始化代码改为RuntimeTypeAdapterFactory.of(Shape.class, "shapeType", true),第三个参数设为true即可自动忽略该字段。

内容的提问来源于stack exchange,提问作者Lulex97

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 15:24:05