1

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

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

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

所以我将空值写入 ByteArrayOutputStream,然后当我从该流中检索字节而不是找到 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。这是怎么回事?

4

2 回答 2

12

首先,你写的时候不是什么都写null。您正在编写一个空值。序列化过程必须确保当你反序列化时,你会得到一个null返回,所以它必须以某种方式表示。开始时也可能有开销来标记流的开始。

同样,当您写“A”时,您不仅仅是在输入“A”字符。您正在序列化一个完整的 String 对象。这必须包含反序列化器稍后重建具有相同值的 String 对象的信息。所以有类型信息和内容。内容本身也将占用超过一个字节,因为 Java 在内部将 String 表示为char2 字节值的数组,并且还因为字符串的长度必须以某种方式编码(实际上我什至很惊讶他们'会把所有这些都放在8个字节中)。

编辑:我已经查看了此页面上的解释。我们可以使用它来了解您获得的结果。

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

  • 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,代表一个新的String
  • 00 01:字符串的长度(1)
  • 65:“A”的 UTF8 表示。

对于最后一个字节,我显然有点错误:即使 Java 在内部使用 2 字节表示 char,它也使用 UTF8 对字符串进行编码,它只使用一个字节来表示字符“A”。

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

于 2013-02-23T20:27:30.150 回答
2

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

于 2013-02-23T20:29:26.237 回答