【问题标题】:Can I serialize an ArrayList without serializing objects which holds?我可以在不序列化持有的对象的情况下序列化 ArrayList 吗?
【发布时间】:2016-06-05 03:11:40
【问题描述】:

我的代码中的一些对象出现在多个列表/地图中。例如:对象 Question myQuestion 在 ArrayList java 和 ArrayList 序列化中。据我所知,Gson 将 ArrayList 中的对象与 ArrayList 本身一起序列化。为了测试它,我运行了以下代码:

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

public class serTries {
    public static void main(String[] args) {
    List<Player> players=new ArrayList<>();
    List<Player> secondaryPlayer =new ArrayList<>();
    for(int i=0;i<3;i++) {
        players.add(i, new Player("John " + i));
        secondaryPlayer.add(players.get(i));
    } //creating 3 Player objects and putting them in 2 different lists.

        try {
                Gson gson = new Gson();
            String ser=gson.toJson(players);
            String secondarySer=gson.toJson(secondaryPlayer);
            Type ct = new TypeToken<ArrayList<Player>>(){}.getType();
                    System.out.println("First list:\n" + ser + "\nSecond list:\n" + secondarySer);
}catch( Exception e)
    {
        e.printStackTrace();
} } }

它产生以下内容:

第一个列表:
[{"name":"John 0"},{"name":"John 1"},{"name":"John 2"}]
第二个列表:
[{"name":"John 0"},{"name":"John 1"},{"name":"John 2"}]

当我通过键入创建一个新列表时

List<Player> deserializedPlayers = gson.fromJson(ser, ct);  
List<Player> deserializedSecondaryPlayers = gson.fromJson(secondarySer, ct);

它创建了 6 个不同的对象(第一个列表中的 3 个玩家,第二个列表中的 3 个。)

我的问题是,有什么方法可以让我可以序列化/反序列化一个名为 onlinePlayers 的列表,它引用“John 1”的一个实例,它也恰好在 List allPlayers 中,而无需复制“John 1”同时仍然引用该对象?
我猜当我反序列化 allPlayers 时,它会创建与原始对象不同的对象,因此在线玩家无法在反序列化后仍然引用同一个对象。我应该编写一个自定义方法在反序列化后将新创建的“John 1”实例添加到 onlinePlayers 吗?

谢谢

【问题讨论】:

标签: java json serialization collections gson


【解决方案1】:

我可以在不序列化保存的对象的情况下序列化 ArrayList 吗?

简短的回答。没有。

序列化的重点是您可以从序列化中重建原始对象的副本。如果您不包含列表元素的序列化,那么您将无法重建列表。

我认为您需要将尝试序列化的列表类型更改为名称列表,而不是玩家列表。或者,考虑使用数据库而不是“哑”序列化。


我的问题是,有什么办法可以让我反序列化一个名为 onlinePlayers 的列表,它指的是“John 1”的一个实例,它也恰好在 List allPlayers 中,没有在引用该对象的同时复制“John 1”?

如果您使用 Java 对象序列化,您可以在 Player 对象上实现 readResolve 方法,该方法查找正在反序列化的对象并将其与“全局”内存数据结构进行比较。 (但这在许多层面上是概念上的错误。)

您可以使用 GSON 自定义反序列化器执行类似的操作。或者,您可以使用基于事件的 JSON 阅读器并使用事件来提取您需要的信息。

但我认为这是错误的做法。


这是问题的关键。

但是,我想从玩家列表(包含数千个对象)中提取数据...

如果您有数千个对象,则序列化/反序列化是错误的解决方案:

  • 要更新,您需要序列化/写入 整个 列表及其包含的所有对象。每一次。即使你只做了一点点改变。

  • 要阅读,您需要完成大部分反序列化工作,即使是您提议的“hack”。

  • 没有简单/快速的方法来对序列化表单进行查询。

  • 有时您需要将整个反序列化的对象图保存在内存中。这无法扩展。

你应该使用某种数据库。

【讨论】:

  • 标题具有误导性。实际问题是关于反序列化,而不是序列化。问题本质上是:当第二次反序列化{"name":"John 1"} 时,它当前创建了一个新的Player 对象。是否可以将其更改为使用第一次反序列化中的现有 Player[name=John 1] 对象? 请参阅“我的问题是...”开头的段落。当标题与实际问题不同步时,讨厌它。
  • 这就是我认为的替代解决方案。但是,我认为每次有人检查在线玩家时从玩家列表(包含数千个对象)中提取数据对于性能而言毫无意义。例如,如果有一个选项允许人们在查看在线玩家时查看玩家的位置,则代码必须从 allPlayers 列表中找到相应的玩家并检查他们的 .location 字段。所以我认为直接将播放器对象放在 onlinePlayers 中会好得多。我想我得再想一想,显然我走错了路。
  • 如果您有一个包含 1000 个玩家的玩家列表,您不应该使用序列化。使用数据库。
  • @Stephen 我不知道从哪里开始。你能指出我正确的方向吗?我是否仍然需要序列化对象才能将它们放入数据库中?
  • 不,您不需要序列化对象即可将它们放入数据库。您可以从阅读以下内容开始:docs.oracle.com/javase/tutorial/jdbc。选择合适的数据库将是另一个问题...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-04
  • 2012-08-06
相关资源
最近更新 更多