正如数据流支持基本数据类型的I / O一样,对象流(object streams)也支持对象的I / O。大多数(但不是全部)标准类支持其对象的序列化。那些确实实现了标记接口Serializable的代码。
对象流类是 ObjectInputStreamObjectOutputStream。这些类实现 ObjectInputObjectOutput,它们是DataInputDataOutput的子接口。这意味着数据流中涵盖的所有基本数据I / O方法也都在对象流中实现。因此,对象流可以包含基本值和对象值的混合。ObjectStreams示例说明了这一点。ObjectStreams创建与DataStreams相同的应用程序,但进行了一些更改。首先,价格现在是 BigDecimal对象,以更好地表示小数值。其次,将一个 Calendar对象写入数据文件,指示发票日期。
如果readObject()未返回预期的对象类型,则尝试将其强制转换为正确的类型可能会抛出ClassNotFoundException。在这个简单的示例中,这不可能发生,因此我们不会尝试捕获异常。相反,我们通过添加ClassNotFoundExceptionmain方法的throws子句中来通知编译器我们已经知道该问题。

复杂对象的输出和输入

writeObjectreadObject方法使用起来很简单,但它们包含了一些非常复杂的对象管理逻辑。对于像Calendar这样的仅封装基本值的类,这并不重要。但是许多对象包含对其他对象的引用。如果readObject要从流中重构对象,则它必须能够重构原始对象所引用的所有对象。这些其他对象可能有自己的引用,依此类推。在这种情况下,writeObject遍历对象引用的整个Web,并将该Web中的所有对象写入流。因此,单次调用writeObject可能会导致将大量对象写入流中。
下图演示了这一点,其中writeObject调用编写单个名为a的对象。该对象包含对对象bc的引用,而b包含对de的引用。调用writeobject(a)不仅会写入a,而且还会写入重构a所需的所有对象,因此也将编写此Web中的其他四个对象。 当readObject读回a时,其他四个对象也将被读回,并且所有原始对象引用都将保留。
对象流 - 图1
多个引用对象的I / O
您可能想知道如果同一流上的两个对象都包含对单个对象的引用会发生什么。当它们被读回时,它们都将引用一个对象吗?答案是“yes”。一个流只能包含一个对象的一个副本,尽管它可以包含对该对象的任意数量的引用。因此,如果您明确将对象两次写入流中,则实际上只写入了两次引用。例如,如果以下代码将一个对象ob两次写入流:

  1. Object ob = new Object();
  2. out.writeObject(ob);
  3. out.writeObject(ob);

每个writeObject都必须与一个readObject匹配,因此读回流的代码将如下所示:

  1. Object ob1 = in.readObject();
  2. Object ob2 = in.readObject();

这将导致两个变量ob1ob2,它们是对单个对象的引用。
但是,如果将单个对象写入两个不同的流,则该对象将被有效地复制-读回两个流的单个程序将看到两个不同的对象。