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

Java 如何在不知道序列化内容的情况下读取ObjectInputStream?,java,serialization,Java,Serialization,下面是一个示例代码,其中对列表、字符串和映射进行了序列化和反序列化。假设我需要通过电线发送文件。接收客户端如何知道反序列化是按列表、字符串和映射的顺序进行的?他怎么知道要把被阅读的对象投射到什么地方 public static void serializeBunchOfObjects() throws FileNotFoundException, IOException { List<String> foo = new ArrayList<String>();

下面是一个示例代码,其中对
列表
字符串
映射
进行了序列化和反序列化。假设我需要通过电线发送
文件
。接收客户端如何知道反序列化是按列表、字符串和映射的顺序进行的?他怎么知道要把被阅读的对象投射到什么地方

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();
}
public static void serializeBunchOfObjects()抛出FileNotFoundException,IOException{
List foo=new ArrayList();
字符串str=“foo”;
Map Map=newhashmap();
ObjectOutputStream oos=新的ObjectOutputStream(新文件输出流(“foo”));
oos.writeObject(foo);
oos.writeObject(str);
oos.writeObject(映射);
oos.close();
}
public static void deserializeBunchOfObjects()引发FileNotFoundException、IOException、ClassNotFoundException{
ObjectInputStream ois=新ObjectInputStream(新文件输入流(“foo”);
List foo=(List)ois.readObject();
String str=(String)ois.readObject();
映射器=(Map)ois.readObject();
}

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

编辑

首先,您必须知道将序列化哪些类型的对象,然后可以为标头创建解析器

我不能提供一个完整的例子,但我可以帮助您构造标题。如果操纵字符串、字符串列表和映射,则标题可能如下所示:

List<String> header = new List<String>();
header.add("list-of-string");
header.add("string");
header.add("map");
列表头=新列表();
header.add(“字符串列表”);
标题。添加(“字符串”);
标题。添加(“地图”);

我想为@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;
}
这样,至少您有一种简单的方法来定义将序列化的各个字段。包装器的额外空间和时间开销将非常小

现在,您仍然可以使用@Lynch的建议,首先编写一个
字符串来表示消息类型

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);
}

“接收客户端如何知道反序列化是按列表、字符串、映射的顺序进行的?”这个问题没有意义。客户机怎么知道它是一个对象流呢?客户端如何知道发送对象的目的是什么?任何客户机-服务器系统都有一个应用程序协议,并且两端都应该实现它。instanceof操作符将告诉您每个对象实际上是什么。
final MessageWrapper received = (MessageWrapper) ois.readObject();
switch (received.getType())
{
  case FOO:
    return handleFoo((FooMessage) received);
  case BAR:
    return handleBar((BarMessage) received);
}