私はこれについて混乱しています。FileOutputStream
Serializable クラスの実装を行うときは、などのクラスを使用する必要があるためObjectOutputStream
です。それでは、これらのクラスを使用して、オブジェクトをファイルに出力したり、ファイルからオブジェクトを入力したりして、オブジェクトのステータスを直接維持することはできませんか? 最初に Serializable を実装してから、同じことを行う必要があるのはなぜですか?
4 に答える
このように理解して...
Serializable は、クラスのオブジェクトをバイト ストリームに変換し、必要に応じて最終的に Java オブジェクトに戻すことができることを示すマーカー インターフェイスです。最初は、すべてのクラスがシリアライズ可能であるべきだと思うかもしれませんが、それは正しくありません。
読み取り対象のファイル ハンドルを持つ InputStreams と OutputStreams。ストリームが利用できなくなると、そのファイル ハンドルは閉じられます。したがって、このインスタンスでのシリアル化は意味がありません。逆シリアル化はそのハンドルを復元しません。
これは、Serializable としてマークする必要がある理由に答える必要がありますか?
オブジェクトの書き込み方法または読み取り方法を定義するメソッドを実装します。これは自分で定義する必要があるため、これらすべてのストリーム オブジェクトと readObject、writeObject メソッドが必要です。これにより、この概念が少しでも理解できるようになることを願っています。
Serializableは単なるマーカー インターフェイスです。つまり、実際にシリアル化を行うコードに、このクラスを問題なくシリアル化できることを (プログラマーが) 知っている (または希望する :-)) ことを通知するために使用されます。
シリアライゼーション自体は、オブジェクトを格納または送信できるもの、つまりバイト ストリームとして変換することです。シリアライゼーションを、ネスカフェを作るために使用される技術であるフリーズドライと比較できます。すべての水が除去され、コーヒー エッセンスのみが瓶に保存されます。メソッドではなく、オブジェクトの状態 (フィールド値) のみがバイトストリームに変換されます。
fvu が既に述べたように、シリアライゼーションは、クラスのインスタンスをバイト配列に変換するプロセスであり、その逆も同様です。Java のすべてのクラスをバイト配列に変換できるわけではありません (Thread
クラスについて考えてみてください。スレッドをバイト配列に変換しても意味がないだけです) Serializable
。変換できるオブジェクト。
Serializable
は単なるマーカー インターフェイスであり、メソッドを実装する必要はありません。ほとんどの場合、これで十分です。シリアル化可能なオブジェクトにインターフェイスを実装させ、デフォルトの動作を使用するだけです。
そのデフォルトのシリアライゼーション動作は、 クラスObjectInputStream
とObjectOutputStream
クラスに実装されています。FileInputStream
とFileOutputStream
は、ディスク上のファイルからデータを読み書きするための異なるクラスです。
オブジェクトをディスクに書き込みたい場合は、次のようなものを使用する必要があります。
MyObject obj = ... // your object instance
ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream("/path/to/file"));
stream.writeObject(obj);
オブジェクトを読み戻すには、次のものが必要です。
ObjectInputStream stream = new ObjectInputStream(new FileInputStream("/path/to/file"));
MyObject obj = (MyObject) stream.readObject();
ただし、オブジェクト インスタンスをディスクではなくメモリにシリアライズ/デシリアライズする場合は、次のようにします。
MyObject obj = ... // your object instance
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
byte[] data = baos.toByteArray();
バイト配列からオブジェクトを読み取る部分は非常に簡単なので省略しますが、JVM によって提供されるすべての異なる入出力ストリームを使用できる巨大な組み合わせを考えてみてください。
上記の例では、デフォルトのシリアル化動作を使用しています。Serializable
ただし、シリアル化する特定のクラスに、インターフェイスを実装していない他のクラス インスタンスへの参照が含まれているシナリオに直面する可能性があります。これらの参照を修飾子でマークしてtransient
、デフォルトのシリアライゼーション動作がそれらを無視するようにする必要があります。また、オブジェクト インスタンスをシリアライズ/デシリアライズしようとするときに呼び出されるプライベート メソッドreadObject
とメソッドを提供するデフォルトの動作をオーバーライドする必要があります。writeObject
さらに、一部のクラスは、シリアル化が発生したときに代替オブジェクト (別のシリアル化可能なクラスのオブジェクト インスタンス) を提供する場合があります。その置換オブジェクトには、元のクラスをその置換オブジェクトから復元できる方法で、元のクラスの状態が含まれます。writeReplace
この動作は、元のクラスのメソッドとreadReplace
置換クラスのメソッドを提供して実装されます。元のクラスと置換クラスの両方がインターフェイスを実装する必要がありSerializable
ますが、置換オブジェクトのデータだけがシリアル化されることに注意してください。
最後になりましたが、インターフェイスを実装するデフォルトのシリアライゼーション プロトコルを完全にオーバーライドするオプションがありExternalizable
ます。これはそのままではマーカー インターフェイスではなく、Serializable
オブジェクトの状態を配列に変換するメソッドを実装する必要があります。ObjectInputStream
/ObjectOutputStream
ペアを使用して、外部化可能なオブジェクト インスタンスをシリアル化 (外部化??)しますが、クラスをバイト配列に変換するロジックは、JVM によって提供されるものではなく、クラスで作成したものになります。クラスの実装。Externalizable
この情報はすべて、thinksteep がコメントとして提供したリンクにあります。
シリアル化は、オブジェクトを取得してバイト配列に書き込むプロセスです (後でバイト配列からオブジェクトに読み取ります)。
ObjectOutputStream は内部でシリアライゼーションを使用し、シリアライズを使用してオブジェクトを byte[] に変換し、それを出力に書き込みます。