文档

Java™教程
隐藏目录
对象流
导航:基本的Java类
课程:基本I/O
章节:I/O流

对象流

与数据流支持原始数据类型的I/O一样,对象流支持对象的I/O。大多数标准类都支持其对象的序列化,但并非全部。实现了标记接口Serializable的类支持对象的序列化。

对象流类是ObjectInputStreamObjectOutputStream。这些类实现了ObjectInputObjectOutput,它们是DataInputDataOutput的子接口。这意味着在对象流中也实现了在数据流中讨论的所有原始数据I/O方法。因此,对象流可以包含原始值和对象值的混合。示例ObjectStreams演示了这一点。 ObjectStreams创建与DataStreams相同的应用程序,但有几个变化。首先,价格现在是BigDecimal对象,以更好地表示分数值。其次,写入数据文件时,还写入了一个Calendar对象,表示发票日期。

如果readObject()没有返回预期的对象类型,尝试将其强制转换为正确的类型可能会抛出ClassNotFoundException。在这个简单的例子中,这种情况不会发生,所以我们不尝试捕获异常。相反,我们通过将ClassNotFoundException添加到main方法的throws子句中,通知编译器我们意识到了这个问题。

复杂对象的输出和输入

writeObjectreadObject方法使用起来很简单,但它们包含了一些非常复杂的对象管理逻辑。对于像Calendar这样只封装原始值的类来说,这并不重要。但是,许多对象包含对其他对象的引用。如果readObject要从流中重新构建一个对象,它必须能够重新构建原始对象所引用的所有对象。这些额外的对象可能有它们自己的引用,依此类推。在这种情况下,writeObject遍历整个对象引用网络,并将该网络中的所有对象写入流。因此,单个writeObject调用可能导致大量对象被写入流中。

这在下图中演示,其中调用writeObject来写入一个名为a的单个对象。该对象包含对对象bc的引用,而b包含对de的引用。调用writeobject(a)不仅写入a,还写入重新构建a所需的所有对象,因此该网络中的其他四个对象也被写入。当通过readObject读回a时,其他四个对象也被读回,并且所有原始对象引用被保留。

多个引用对象的I/O

多个引用对象的I/O

你可能想知道如果同一个流中的两个对象都包含对单个对象的引用会发生什么。当它们被读回时,它们是否都引用同一个对象?答案是“是”。流只能包含一个对象的副本,尽管可以包含任意数量的引用。因此,如果你显式地将一个对象写入流两次,实际上只是将引用写入两次。例如,如果以下代码将一个对象ob两次写入流中:

Object ob = new Object();
out.writeObject(ob);
out.writeObject(ob);

每个writeObject都必须与一个readObject相匹配,因此读取流的代码将类似于:

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

这将得到两个变量ob1ob2,它们都是对同一个对象的引用。

然而,如果一个对象被写入两个不同的流中,它实际上是复制的 - 一个程序读取两个流将看到两个不同的对象。


上一页: 数据流
下一页: 文件I/O(包含NIO.2)