如何在不知道序列化的情况下读取ObjectInputStream?

时间:2014-03-13 01:30:44

标签: java serialization

以下是序列化和反序列化ListStringMap的示例代码。假设我需要通过电汇发送file。接收客户端如何知道反序列化是按List,String,Map的顺序排列的?他怎么知道要把被读物体投射到什么地方?

public static void serializeBunchOfObjects() throws FileNotFoundException, IOException {
    List<String> foo = new ArrayList<String>();
    String str = "foo";
    Map<Integer, Integer> map = new HashMap<Integer, Integer>();

    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("foo"));
    oos.writeObject(foo);
    oos.writeObject(str);
    oos.writeObject(map);

    oos.close();
}

public static void deserializeBunchOfObjects() throws FileNotFoundException, IOException, ClassNotFoundException {
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("foo"));
    List<String> foo = (List)ois.readObject();
    String str = (String) ois.readObject();
    Map<Integer, Integer> mapper = (Map) ois.readObject();
}

2 个答案:

答案 0 :(得分:2)

我想向@Lynch提出一个单独的解决方案(或至少是一个变体)。

当您向客户端发送消息时,是否有一组已定义的消息类型?如果这样做,您可以在消息体周围定义包装器对象,它可以作为一种标头。

您可以定义一个FooMessage,其中包含您要序列化的字段:

public class FooMessage
{
  private static final long serialVersionUID = 1L;

  private final List<String> theList;
  private final String string;
  private final Map<String, Object> theMap;
}

然后,不是单独序列化部件,而是序列化包装器&#34;

final FooMessage msg = new FooMessage(...);

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("foo"));
oos.writeObject(msg);

这样,至少你有一种简单的方法来定义将被序列化的各个字段。包装器的额外空间和时间开销将非常小。

现在,您仍然可以使用@Lynch建议编写String来首先表示消息类型......

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("foo"));
oos.writeUTF("FooMessage");
oos.writeObject(msg);

...或者,如果消息数量非常小,您可以在没有字符串的情况下离开并简单地测试对象类型:

final Object received = ois.readObject();
if (received instanceof FooMessage)
{
  ...
}
else if (received instanceof BarMessage)
{
}

最后一个变体是您可以从超类继承您的具体消息类型,该类包含表示为枚举的类型:

public abstract class MessageWrapper
{
  public MessageWrapper(YourMessageType type)
  {
    this.type = type;
  }

  public abstract YourMessageType getType();
}

public class FooMessage extends MessageWrapper
{
  public FooMessage()
  {
    super(YourMessageType.FOO);
  }
}

这允许你这样做:

final MessageWrapper received = (MessageWrapper) ois.readObject();
switch (received.getType())
{
  case FOO:
    return handleFoo((FooMessage) received);
  case BAR:
    return handleBar((BarMessage) received);
}

答案 1 :(得分:1)

您应首先序列化标题,告诉您文件其余部分的内容。这样,您反序列化的第一件事是标题(换句话说是文件结构的表示)。

修改

首先,你必须知道要序列化的对象类型,然后你可以为标题创建一个解析器。

我无法提供完整的示例,但我可以帮助您构建标题。如果你操纵string,string-of-string和map,那么你的标题可能如下所示:

List<String> header = new List<String>();
header.add("list-of-string");
header.add("string");
header.add("map");