このページを正しく表示するには、ブラウザでJavaScriptを有効にする必要があります。
コース: 重要なクラス
レッスン: 基本的なI/O
セクション: I/Oストリーム
オブジェクト・ストリーム
ホームページ > 重要なクラス > 基本的なI/O

オブジェクト・ストリーム

データ・ストリームがプリミティブ・データ型のI/Oをサポートするのと同様に、オブジェクト・ストリームはオブジェクトのI/Oをサポートします。 すべてではないものの大半の標準クラスでは、そのオブジェクトの直列化(シリアライズ)がサポートされています。 クラスを直列化可能にするには、マーカー・インタフェースのSerializableを実装します。

オブジェクト・ストリーム・クラスは、ObjectInputStreamObjectOutputStreamです。 これらのクラスは、DataInputのサブインタフェースであるObjectInputか、DataOutputのサブインタフェースであるObjectOutputを実装しています。 つまり、データ・ストリームで扱われるプリミティブ・データのI/Oメソッドはすべて、オブジェクト・ストリームでも実装されています。 このため、オブジェクト・ストリームには、プリミティブ値とオブジェクト値を同時に含めることができます。 このことは、サンプル・プログラムのObjectStreamsで確認できます。 ObjectStreamsで作成されるアプリケーションは、前述のサンプル・プログラムDataStreamsで作成されるものと基本的には同じですが、いくつか変更点があります。 まず、価格には、小数値をより適切に表すBigDecimalオブジェクトを使用しています。 また、請求書の日付を表すCalendarオブジェクトを、データ・ファイルに書き込んでいます。

readObject()で返されるオブジェクトの型が期待したものと異なる場合、正しい型にキャストしようとするとClassNotFoundExceptionがスローされることがあります。 この単純なサンプル・プログラムではこうした事態は発生しないため、例外のキャッチはしていません。 代わりに、mainメソッドのthrows句にClassNotFoundExceptionを追加することで、このような問題を認識していることをコンパイラに通知しています。

複雑なオブジェクトの入出力

writeObjectメソッドとreadObjectメソッドは、簡単に使用できる一方で、ある非常に高度なオブジェクト管理ロジックを含んでいます。 このことは、Calendarのような、単にプリミティブ値をカプセル化するだけのクラスには重要ではありません。 しかし、多くのオブジェクトには他のオブジェクトへの参照が含まれています。 readObjectがストリームからオブジェクトを再構成する場合、元のオブジェクトが参照していたすべてのオブジェクトを再構成できる必要があります。 さらに、これらのオブジェクトもまた別のオブジェクトを参照している可能性があり、こうした参照関係が延々と続く場合もあります。 このような状況において、writeObjectは網状に広がったオブジェクト参照構造の全体をトラバースして、その構造内のすべてのオブジェクトをストリームに書き込みます。 したがって、writeObjectを1回呼び出しただけで、大量のオブジェクトがストリームに書き込まれる場合があります。

この状況を、次の図で示します。ここでは、aという名前の1つのオブジェクトを書き込むために、writeObjectが呼び出されます。 このオブジェクトには、bおよびcというオブジェクトへの参照が含まれ、さらにbにはdおよびeへの参照が含まれます。 writeobject(a)を呼び出すと、aだけではなく、aの再構成に必要なすべてのオブジェクトも書き込まれます。このため、この網状の構造内にある他の4つのオブジェクトも書き込まれることになります。 areadObjectによって再度読み取られると、他の4つのオブジェクトも同様に読み取られ、元のオブジェクト参照のすべてが維持されます。

I/O of multiple referred-to objects

複数の参照先オブジェクトのI/O

同じストリーム上の2つのオブジェクトが、同じ1つのオブジェクトを参照している場合はどうなるか、考えてみましょう。 どちらのオブジェクトも、再度読み取られたときに1つのオブジェクトを参照するのでしょうか。 答えは、"参照します"。 ストリームにはオブジェクトのコピーは1つしか含めることはできませんが、そのオブジェクトへの参照はいくつでも含めることができます。 したがって、オブジェクトをストリームに2回明示的に書き込むと、実際は単にその参照を2回書き込むことになります。 たとえば、次のコードでは、obというオブジェクトをストリームに2回書き込んでいます。
Object ob = new Object();
out.writeObject(ob);
out.writeObject(ob);
それぞれのwriteObjectreadObjectに対応させる必要があるので、このストリームを再度読み取るコードは次のようになります。
Object ob1 = in.readObject();
Object ob2 = in.readObject();
このコードを実行すると、ob1ob2という2つの変数は、同じ1つのオブジェクトへの参照となります。

ただし、1つのオブジェクトが別々の2つのストリームに書き込まれる場合は、そのオブジェクトは実際に複製されます。つまり、1つのプログラムで両方のストリームを再度読み取ると、2つの異なるオブジェクトを確認できます。


サンプル・プログラムで問題が発生した場合は、 Compiling and Running the Examples: FAQsを参照してください。
フィードバックをお寄せください。さまざまなご意見をお待ちしております。

前のページ: データ・ストリーム
次のページ: ファイルI/O(NIO.2を含む)