Object Streams
就像数据流支持原始数据类型的 I/O 一样,对象流也支持对象的 I/O。大多数(但不是全部)标准类支持其对象的序列化。那些确实实现了标记interfaceSerializable的对象。
对象流类是ObjectInputStream和ObjectOutputStream。这些类实现ObjectInput和ObjectOutput,它们是DataInput
和DataOutput
的子interface。这意味着Data Streams中涵盖的所有原始数据 I/O 方法也都在对象流中实现。因此,对象流可以包含原始值和对象值的混合。 ObjectStreams示例说明了这一点。 ObjectStreams
创建与DataStreams
相同的应用程序,但有一些更改。首先,价格现在是BigDecimal个对象,以更好地表示分数值。其次,将Calendar对象写入数据文件,指示发票日期。
如果readObject()
没有返回预期的对象类型,则try将其转换为正确的类型可能会抛出ClassNotFoundException。在这个简单的示例中,这不可能发生,因此我们不会trycatch异常。相反,我们通过在main
方法的throws
子句中添加ClassNotFoundException
来通知编译器我们已经知道该问题。
复杂对象的输出和 Importing
writeObject
和readObject
方法易于使用,但是它们包含一些非常复杂的对象 管理 逻辑。对于像 Calendar 这样的仅封装原始值的类,这并不重要。但是许多对象包含对其他对象的引用。如果readObject
要从流中重构对象,则它必须能够重构原始对象所引用的所有对象。这些其他对象可能有自己的引用,依此类推。在这种情况下,writeObject
遍历对象引用的整个 Web 并将该 Web 中的所有对象写入流中。因此,一次调用writeObject
可以导致将大量对象写入流中。
在下图中演示了这一点,其中调用了writeObject
以写入名为 a 的单个对象。该对象包含对对象 b 和 c 的引用,而 b 包含对 d 和 e 的引用。调用writeobject(a)
不仅会写入 a ,而且还会写入重构 a 所需的所有对象,因此也将写入此 Web 中的其他四个对象。当readObject
读回 a 时,其他四个对象也会被读回,并且所有原始对象引用都将保留。
多个引用对象的 I/O
您可能想知道,如果同一流上的两个对象都包含对单个对象的引用,将会发生什么情况。回读它们是否都引用一个对象?答案是“是”。一个流只能包含一个对象的一个副本,尽管它可以包含对该对象的任何数量的引用。因此,如果您将一个对象显式地写入流两次,则实际上仅写入了两次引用。例如,如果以下代码将对象ob
两次写入流:
Object ob = new Object();
out.writeObject(ob);
out.writeObject(ob);
每个writeObject
必须由readObject
匹配,因此读回流的代码将类似于以下内容:
Object ob1 = in.readObject();
Object ob2 = in.readObject();
这将导致两个变量ob1
和ob2
,它们是对单个对象的引用。
但是,如果将单个对象写入两个不同的流,则该对象将被有效地复制-读回两个流的单个程序将看到两个不同的对象。