使用gson进行序列化/反序列化时无法强制转换为子类

rkttyhzu  于 2022-11-06  发布在  其他
关注(0)|答案(1)|浏览(276)

我定义了一个带有ArrayList变量的Record类,它存储了Base类的示例列表(这些示例实际上是Sub类的示例)。
样本代码

public class Record {
  private ArrayList<Base> list;

  public void Record() {
    list = new ArrayList<>();
  }
  public add(Base instance) {
    list.add(instance) // instance is of Sub class
  }

  private class Sub extends Base {}
}

我使用gson库将其序列化为共享首选项

SharedPreferences.Editor editor = sharedPreferences.edit();
    Gson gson = new Gson();
    editor.putString(KEY, gson.toJson(record)); // an Arraylist of Record instances
    editor.commit();

但当将其反序列化回Record示例的ArrayList,并试图通过将其强制转换为Sub类来从列表中的示例调用Sub类的方法时,我收到了类似“java.lang.ClassCastException:无法将类Base强制转换为类Sub”

Gson gson = new Gson();
Type type = new TypeToken<TreeMap<String, Record>>() {}.getType();
TreeMap<String, Record> records = gson.fromJson(sharedPreferences.getString(RECORDS_KEY, null), type);

// trying to call the method from the subclass
((Sub)records.get("a").list[0]).methodFromSub();
taor4pac

taor4pac1#

Gson接收的java.lang.reflect.TypeTreeMap<String, Record>,而Record中的字段list类型是ArrayList<Base>。因此,Gson将list反序列化为ArrayList<Base>NOTArrayList<Sub>。要指定list类型以让Gson知道反序列化SubBase,请尝试以下代码:

class Base {
    public String base;
}

class Record<T extends Base> {
    public ArrayList<T> list;

    public void Record() {
        list = new ArrayList<>();
    }

    public void add(T instance) {
        list.add(instance); // instance is of Sub class
    }

    class Sub extends Base {

        public String sub;

        public String getBaseAndStub() {
            return (base != null ? base : "") + (sub != null ? sub : "");
        }
    }
}

我已经测试了上面代码,它工作正常:

public void test() {
    String json = "{\n" +
            "  \"haha\": {\n" +
            "    \"list\": [\n" +
            "      {\n" +
            "        \"sub\": \"sub\",\n" +
            "        \"base\": \"base\"\n" +
            "      }\n" +
            "    ]\n" +
            "  }\n" +
            "}";
    Gson gson = new Gson();
    Type type = new TypeToken<TreeMap<String, Record<Record.Sub>>>() {}.getType();
    TreeMap<String, Record<Record.Sub>> map = gson.fromJson(json, type);
    System.out.println(map.get("haha").list.get(0).getBaseAndStub());
    // Output: basesub
}

相关问题