ーシリアライズって何なのか日本語で直列化とか言われるらしいです。要は、オブジェクトの状態をStreamの状態(1バイトずつ読み書きできるバイト配列状のデータ構造)に変換することをシリアライズと言うようです。逆にStreamの状態をオブジェクトに戻してやることをデシリアライズと言います。}}例えばこんなPersonクラスがあったとする。インスタンスをシリアライズすると、こんな形になるかもしれない。(シリアライズの形式は問わない。どんな形式でも、バイト列になっていて、復元可能なら良い。&lt;age&gt;32&lt;/age&gt;&lt;/jp.xet.sample.Person&gt;いや、またはこんな形かもしれない。Daisuke,Miyamoto,32ちなみに、ファイルってのは、1バイトずつのデータが並んでいる、要は直列の状態だ。ファイルに保存できる状態=ストリームと考えて良いと思う。この状態に変換することを「シリアライズ」と呼ぶわけだ。オブジェクトは大抵「オブジェクトグラフ」と呼ばれる網状のデータ構造であって、直列データ構造ではない。このグラフ構造を直列構造に変換するのがシリアライズ。その逆変換がデシリアライズ。「どんな直列なのか」は問わない。XMLでもよし、カンマ区切りでもよし、バイナリでもよし。相互変換ができて、必要なときにシリアライズ・デシリアライズができればよいのだ。先ほどのPersonクラスは、簡単に「シリアライズ可能であること」を保証できました。逆に、シリアライズが困難(不可能ということはあり得ないらしい)なケースとはどういう状況か。java.io.InputStreamやjava.sql.Connectionが代表例としてよく挙げられます。コネクションをシリアライズしてファイルに保存したとして...。次にこのコネクションをデシリアライズした時、またコネクションを以前と同じように利用できるでしょうか。あと、ファイル化できるということは、ネットワークを介してファイル転送して、遠隔のコンピュータとオブジェクトのやり取りができることを意味します。InputStreamをシリアライズして、別のコンピュータに送ってデシリアライズして使う...。要はネットワークファイルシステムの実装ですかね。実現が非常に難しいことがわかると思います。ConnectionやInputStream自身がシリアライズ困難であるとともに、これらのインスタンスをフィールドに持つインスタンスもシリアライズ困難です。PersonクラスのフィールドにConnectionやInputStreamがあった場合、このPersonクラスはシリアライズ困難、ということになります。Serializableをimplementsしているにもかかわらず実際にはシリアライズが困難なクラス、というのがいとも簡単に作れてしまう事が分かります。size()で-1を返すリストがいとも簡単に作れてしまうのと、同じなんですけどね。「このクラスはConnectionとかInputStreamとか、シリアライズが困難なモンじゃないよ、ちゃんとシリアライズできるし、デシリアライズしたら元通りに動作する造りになってるよ!」という宣言をしているのがSerializableです。それをimplementsするクラスは、その宣言通り、そういう造りでクラスを設計しなければならんのです。厳密には正直難しくてよくわからん。俺は「自分でそのクラスをシリアライズするロジックを書こうと思った時、それがすんなり書けそうか否か」というビミョーで主観的な判断基準で、何とかやりすごしてますwserialVersionUIDところで、話題を少し変えて。Serializableなクラスを実装すると、しばしばコンパイラが警告を発します。longこいつは、以下のようなフィールドを定義することにより、黙らせることができます。フィールドを定義していませんか?そもそもこの数字、何なの?先ほどのPersonクラスの例でいきます。あるPersonをシリアライズしてファイルにしました。そのファイルをネットワークで転送して、別のマシン(JVM)上でデシリアライズを試みるとします。送信側のPersonクラスと、受信側のPersonクラスが「同じ構造をしていること」が保証できるでしょうか。いう完全修飾名を持っていたとしても、両者に全く同じクラスがロードされているとは限りません。受信側には「年齢フィールドがなく、代わりに誕生日フィールドがあるPersonクラス」が待ち構えているかもしれないのです。このフィールドには「クラス構造のハッシュ値のようなもの」が入っているとされています。クラスのメンバに何か変更があったときは、この数値も変わる、という約束があるんです。送受信側のこの値が一致したらば、正常にシリアライズ・デシリアライズができる、という保証をするのも約束事ですね。いうような固有の値をつけておくのです。シリアライズデータの中にこの数値を仕込んでおくと、デシリアライズ時に「おや、serialVersionUIDの値が一致しねーぞ」ということで、簡単にエラーを特定することができるようになります。いう値をセットした場合。"Miyamoto,Daisuke,32"というデータをbirthData版でデシリアライズすると...。して解釈されるんでしょうね。1970上記の通り、エポックから32ミリ秒後となりました。serialVersionUIDを定義する、ということあるクラスにserialVersionUIDを定義したら、「今後、このクラスの構造が変わった場合は、必ずこの値も更新します」という約束が有効になります。serialVersionUIDによる型の同一性チェックなんか要らない、というアプリケーション特性は「よくあること」だと思います。別にネットワークで転送して別のVMで読み書きなんかしない。1つのVMの中で保存できて読み出しができれば十分なんだ。自分でシリアライズしたものを自分でデシリアライズするだけだから、クラスの構造が変わるなんてあり得ない、という状況。そのアプリケーションを外から見た際、こいつが「シリアライズ時の型同一性チェックに対応したアプリなのか否か」は分からないのです。従って、serialVersionUIDが定義されているかどうか、で判断するのが妥当です。serialVersionUIDを定義していない場合「ああ、シリアライズ時の型同一性チェックに対応する気がないのね」というアピールになる。逆に「わざわざserialVersionUIDを定義しているということは、型同一性チェックに対応しているんだ!」と判断されても文句は言えませんね。serialVersionUIDを定義したのにメンテナンスしなかった場合、「値が一致しているのになぜデシリアライズに失敗するんだ!」とキレられても文句が言えません。ある「そもそもそこまでの保証はしてないよ、必要がないしコストにも見合わないから」と判断したというアピールのためにも、serialVersionUIDは「定義しない」のが現実的だと考えています。まとめと、まぁ、Serializableについて思う所を適当に書いてみました。07:09こんにちは。書いてあることが自分の意見と同じすぎて感動したのですが、一つおかしいところがあるので、ツッコミさせていただきます。serialVersionUIDに関しては、定義をしない場合にはクラスの構造を解釈して勝手にコンパイラが生成してくれます。クラスのフィールドを変更したら勝手に変更してくれます。問題点としては、コンパイラが勝手に計算してくれるので、複数のコンパイラをまたぐ場合に同じ定義のはずだけれども失敗することがある(らしい)ということです。記事に書いてあることとは逆ですね。JavaDocに記載されているのでご参照ください。http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/io/Serializable.html#そもそもSun実装以外のコンパイラを使うことがあるのかという疑問はありますが。#そして、自分は複数のコンパイラ(+VM)で失敗することを見たことがないというか、Sun実装以外のコンパイラを使用したことがない。12:16megascusさん、こんにちは。興味深いコメント、どうもありがとうございます。確かに仕様を参照すると、未定義の場合デフォルト値を自動生成するとの記述がありますね。教えて頂いてありがとうごじます。私もこの記述を読んでもう一つ気になる事が出て来ました。検証コードも必要になり、コメントでお返事するには長過ぎるので、新たなエントリを上げたいと思います。19:28http://d.hatena.ne.jp/daisuke-m/20110527/1306492097スパム対策のためのダミーです。見えても何も入力しないでくださいコメントを書くには、なぞなぞ認証に回答する必要があります。(id:daisuke-m)Java・OO厨。123456789101112131415161718192021222324252627282930TopHatenar最新タイトル[etc]クラスメソッド株式会社に転職しました!またな、山城。License.当ブログ上の都元ダイスケが著作権を持つ全てのコンテンツは、上記条項によりライセンスされております。ライセンスの範囲内での利用に、あらためて許諾は必要ありません。