在writeObject(null)之后期望0字节,而不是找到5个字节,发生了什么?

时间:2013-02-23 20:20:38

标签: java objectoutputstream bytearrayoutputstream

将对象写入ByteArrayOutputStream时,我得到了一些奇怪的结果。

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream os = new ObjectOutputStream(baos);
    os.writeObject(null);

    byte[] objectBytes = baos.toByteArray();
    int objectSize = objectBytes.length;

所以我给ByteArrayOutputStream写了一个null,然后当我从这个流中检索字节而不是找到0个字节时,我发现有5个。字节的值如下 -

  • [0] => -84
  • [1] => -19
  • [2] => 0
  • [3] => 5
  • [4] => 112

如果我将os.writeObject(null)更改为os.writeObject("A"),我会得到8个字节,这些是 -

  • [0] => -84
  • [1] => -19
  • [2] => 0
  • [3] => 5
  • [4] => 116
  • [5] => 0
  • [6] => 65
  • [7] => 8

那么这里发生了什么,如果我写0字节,我希望在检索字节数组时找到字节。然后我看到它增加了5个字节。因此,当我写“A”时,我希望它在字节数组中返回6个字节,但它返回8.这里发生了什么?

2 个答案:

答案 0 :(得分:11)

首先,当你写null时,你什么都不写。您正在写一个空值。序列化过程必须确保在反序列化时,您将获得null,因此必须以某种方式表示。开头可能还有开销标记流的开始。

当你写“A”时,你也不只是把“A”字符。您正在序列化一个完整的String对象。这必须包含反序列化程序的信息,以便稍后重建具有相同值的String对象。所以有类型信息和内容。内容本身也将占用多个字节,因为Java将内部String表示为char的数组,它们是2字节值,并且还因为字符串的长度必须以某种方式编码(实际上我他们甚至惊讶于他们把所有这些只用了8个字节。)

修改:我已经看了this page的解释。我们可以用它来理解你获得的结果。

在第一个示例中,您有以下字节:

  • AC ED(这是-84 -19的十六进制):STREAM_MAGIC。指定这是序列化协议的神奇值。
  • 00 05:STREAM_VERSION。版本5.
  • 70(十六进制表示112):TC_NULL,表示空值。

在你的第二个例子中,实际上你给出的值并不对应。我自己尝试了你的代码并获得了:

  • AC ED:STREAM_MAGIC
  • 00 05:STREAM_VERSION
  • 74:TC_STRING,表示新的字符串
  • 00 01:字符串的长度(1)
  • 65:UTF8表示“A”。

对于最后一个字节,我显然有点不对劲:即使Java在内部使用2字节表示形式的char,它也会使用UTF8编码String,它只使用一个字节作为字符“A”。

格式中的所有特殊值都是类ObjectStreamConstants

中的常量

答案 1 :(得分:2)

Null是一个与其他任何值相同的值。可能存在需要编写的情况。