正如數據流支持原始數據類型的I/O同樣,對象流也支持對象的I/O,大多數(但不是所有)標準類支持其對象的序列化,那些是實現標記接口Serializable的。html
對象流類是ObjectInputStream和ObjectOutputStream,這些類實現ObjectInput和ObjectOutput,它們是DataInput
和DataOutput
的子接口。這意味着數據流中涵蓋的全部原始數據I/O方法也在對象流中實現,所以,對象流能夠包含原始值和對象值的混合。ObjectStreams示例說明了這一點,ObjectStreams
建立與DataStreams
相同的應用程序,並進行了一些更改,首先,價格如今是BigDecimal對象,以更好地表明小數值,其次,將Calendar對象寫入數據文件,指示發票日期。java
若是readObject()
沒有返回預期的對象類型,則嘗試將其強制轉換爲正確的類型可能會拋出ClassNotFoundException,在這個簡單的例子中,這不可能發生,所以咱們不會嘗試捕獲異常,相反,咱們經過向main
方法的throws
子句添加ClassNotFoundException
來通知編譯器咱們已經意識到了這個問題。git
writeObject
和readObject
方法易於使用,但它們包含一些很是複雜的對象管理邏輯,這對像Calendar
這樣的類來講並不重要,它只封裝了原始值,可是許多對象包含對其餘對象的引用,若是readObject
是要從流重建一個對象,它必須可以重建原始對象所引用的全部對象,這些附加對象可能有本身的引用,依此類推。在這種狀況下,writeObject
遍歷整個對象引用網絡,並將該網絡中的全部對象寫入流,所以,對writeObject
的單個調用可能致使將大量對象寫入流。github
下圖演示了這一點,其中調用writeObject
來寫入名爲a
的單個對象,該對象包含對象b
和c
的引用,而b
包含對d
和e
的引用,調用writeobject(a)
不只寫入a
,並且寫入重建a
所需的全部對象,所以該網絡中的其餘四個對象也被寫入。當readObject
讀回a
時,也會讀回其餘四個對象,並保留全部原始對象引用。segmentfault
你可能想知道若是同一個流上的兩個對象都包含對單個對象的引用會發生什麼,當他們被回讀時,他們都會引用一個對象嗎?答案是確定的。一個流只能包含一個對象的副本,儘管它能夠包含對該對象的任意數量的引用,所以,若是你明確地將對象寫入流兩次,那麼你實際上只寫入了兩次引用,例如,若是如下代碼將對象ob
寫入流兩次:api
Object ob = new Object(); out.writeObject(ob); out.writeObject(ob);
每一個writeObject
都必須與readObject
匹配,所以讀迴流的代碼將以下所示:網絡
Object ob1 = in.readObject(); Object ob2 = in.readObject();
這產生兩個變量ob1
和ob2
,它們是對單個對象的引用。oracle
可是,若是將單個對象寫入兩個不一樣的流,則會有效地複製它 — 讀取兩個流的單個程序將看到兩個不一樣的對象。spa