在使用双向引用序列化对象时,如何避免堆栈溢出?

时间:2013-12-12 17:03:55

标签: java libgdx

我的游戏中有对象,我希望能够序列化为JSON。问题是当它们有一个指向“所有者”对象的指针时尝试序列化它们会导致堆栈溢出。

例如:

public class Entity
{

    Vector2 loc;
    Item item;

    public Entity(Vector2 loc)
    {

    this.loc = loc;
    this.item = new Item(this.loc, this);

    }

}


public class Item
{

    Vector2 loc;
    Entity owner;

    public Item(Vector2 loc, Entity owner)
    {

    this.loc = loc;
    this.owner = owner;

    }
}

如果我再打电话

Json json = new Json();
System.out.println(json.prettyprint(instanceOfEntity));

我得到了堆栈溢出。

我意识到这可能是一个架构问题,但我不确定解决问题的最佳方法。这个问题的解决方案是什么?

3 个答案:

答案 0 :(得分:1)

Owner字段设置为transient应该可以解决问题,并避免对序列化进行循环引用:

public class Item
{
    Vector2 loc;
    transient Entity owner;

    public Item(Vector2 loc, Entity owner)
    {
        this.loc = loc;
        this.owner = owner;
    }
}

How does marking a field as transient make it possible to serialise an object

答案 1 :(得分:1)

由于这篇文章最初来自gamedev exchange,我假设您正在使用Libgdx的json解析器,因为它看起来像它。

如果在Libgdx中实现Json.Serializable接口,则可以通过实现write方法来自定义序列化,在write方法中指定如何将对象转换为json字符串。您可以查看libgdx tutorial的更多信息。我还写了一篇关于如何使用Libgdx json解析器的blog

另一个解决方案是对方所说的,删除循环引用

答案 2 :(得分:1)

我认为解决这个问题的最佳方法是通过以某种方式重新构建数据结构来删除循环链接,可能使用某种映射或表来将实体链接到Item。

如果确实必须保留循环引用,那么我建议编写自己的解析器,因为在序列化时忽略所有者将意味着在序列化对象反序列化时不会返回所有者。 / p>

有关如何编写自己的解析器的示例,请访问LibGDX Google Code网站:

Json json = new Json();
json.setSerializer(PhoneNumber.class, new Json.Serializer<PhoneNumber>() {
  public void write (Json json, PhoneNumber number, Class knownType) {
    json.writeObjectStart();
    json.writeValue(number.name, number.number);
    json.writeObjectEnd();
  }

   public PhoneNumber read (Json json, JsonValue jsonData, Class type) {
    PhoneNumber number = new PhoneNumber();
    number.setName(jsonData.child().name());
    number.setNumber(jsonData.child().asString());
    return number;
  }
});
json.setElementType(Person.class, "numbers", PhoneNumber.class);
String text = json.prettyPrint(person);
System.out.println(text);
Person person2 = json.fromJson(Person.class, text);