SerializableインターフェースのserialVersionUIDについて

このQ&Aのポイント
  • serialVersionUIDとは、直列化オブジェクトの送信側と受信側が直列化互換性を検証するために使用されるバージョン番号です。
  • 送信側と受信側は、オブジェクトを保存しているファイル(ストリーム)側と、オブジェクトの読み出しを行うプログラム側を指します。
  • serialVersionUIDの値は単純な値でも問題ありませんが、割り振り方によってはより良い結果が得られることもあります。
回答を見る
  • ベストアンサー

serialVersionUIDについて

SerializableインターフェースのJavadoc(J2SE 5.0を参照しました)で 「バージョン番号は、直列化復元時に、直列化オブジェクトの送信側と受信側が直列化互換性のあるこのオブジェクトのクラスをロードしたかどうかを検証するために使用されます。」 とあるのですが、この説明の「送信側」と「受信側」というのは オブジェクトをファイル保存している場合でいうと 「オブジェクトを保存しているファイル(あるいはそのストリーム)側」が「受信側」で 「そのオブジェクトの読み出しを行っているプログラム側」が「受信側」という理解で正しいでしょうか? serialVersionUIDというのは読み出したオブジェクトが 利用側の想定するクラスと正しいかどうかを判断するために必要という理解で良いのでしょうか? 上記理解が正しい場合、serialVersionUIDというのは「1L」といった 単純な値でも特に問題ないのでしょうか? 「こういう割り振り方にすると良い」といったことはあるのでしょうか? EclipseなどのIDEにはserialVersionUIDを自動で割り振る機能があるそうですが これを利用するメリットは何でしょうか? シリアライズする場合、なぜSerializableインターフェースを 載せなければならない仕様になっているのでしょうか? 最初からすべてのクラスはシリアライズ可能にしておくと 何か不都合があるのでしょうか? 以上、質問が多くなりましたが ひとつでもいいのでご回答よろしくお願いします。

  • Java
  • 回答数2
  • ありがとう数8

質問者が選んだベストアンサー

  • ベストアンサー
  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.2

> 回答文中の受信側JavaVMにロードされたクラスHogeBeanは > serialVersionUIDが「-2L」となっているので > ・・・・これを「-1L」として、・・・・ > serialVersionUIDを同じにするとどうなるのでしょうか? 良いところに気づきましたね。そこも前回敢えて端折った部分です。 結局、Serializableインタフェースの実装も、シリアルバージョンも、 「人間がコンピュータが判断しやすいようにしてあげる」ための物で、 人間にとってはほとんど何の意味も持たないものなんだね~。 ・バージョン同じで中身同じ→普通。 ・バージョン違いで中身同じ→JavaVMは違うものと判断。 ●バージョン同じで中身違い→JavaVMは同じものと判断し、後で何らかの例外が起こる事でしょう。 ・バージョン違いで中身違い→JavaVMは違うものと判断。 >>それは誤解で、Serializableインタフェースを実装しなくてもシリアライズは可能です。 > JavaDocには・・・・ですが、 > anmochi様がおっしゃっている・・・・より一般的な「シリアライズ」と > いうものを考えた場合の話でしょうか? そうです。私の発言はJavaという仕組みではなく、シリアライズの概念と捕らえてください。Sun JavaVMは確かにif(hoge instanceOf Serializable)のチェックを行っています。 ただ、これはあくまで「Sun標準のシリアライザー」での話であり、 シリアライザーも当然自作する事ができますので、その際に if(hoge instanceOf Serializable)をチェックするかどうかは シリアライザー作成者の意識次第です。 Serializableインタフェースが、メソッド宣言も定数も何も無いのに なんでこんなのある、つまりSunは用意したのだろうと思いませんでしたか? 何も中身がないインタフェースでも、 instanceOf SerializableがTrueかFalseかという違いが出てきます。 これが、Serializableインタフェースが存在する理由です。 とにかく、ここでは前述の通り、Serializableインタフェースの実装は JavaVMに対して「このクラスはシリアライズ可能だよ」と教えてあげる ヒントであり、それ以上でもそれ以下でもないという事を改めて述べただけです。 Serializableインタフェースそのものの存在に意味は無い。 「人間がそこに意味を持たせている」だけな訳です。 >>Serializableインタフェースを実装しシリアライズ不可能なクラス、というのも当然作れちゃう。 > JavaにおいてSerializableインタフェースを実装していながら > シリアライズができないパターンというのは > 具体的にどういうソースなのでしょうか? では、そもそも「シリアライズ不可能」とは何か考えてみましょう。 もっとも分かりやすい例だと、ファイルオブジェクトの インスタンスを保持(has-A)するようなクラスはシリアライズできません。 これは、ファイルオブジェクトはOSのファイルディスクリプタと 結び付けられ、ファイルディスクリプタを含めてシリアライズして 別の場所でデシリアライズしても、そのファイルディスクリプタで表される OSがオープンしているファイルが存在するとは限らないからです。 これが「シリアライズ不可能」という事。状態が自分の中で閉じていないという事ですね。 で、再び前述の通り、Serializableインタフェースの実装というのは、 「本当にそのクラスがシリアライズ可能かどうか」とは何の関係もありません。 クラスの作者が恣意的につけるものです。 繰り返しになりますが、 ・Serializableインタフェースの実装は単なる宣言に過ぎない。 ・本当にシリアライズ可能かどうかはクラスの作成者しか分からない。 ・JavaVMがシリアライズ可能性の精査をするのはコストがかかる。 ・シリアライズ可能性はクラス作者に宣言させてそれを信じるしかない。  というか信じるという仕組みの方がみんなが楽でしかも速い。 というのが、Javaにおけるシリアライズ精査の仕組みだという事です。 つまり、クラスの作成者の善意というか正義に任せようという わりといい加減というか、人間くさい仕組みですね。

kyonn2008
質問者

お礼

お礼が遅くなり申し訳ありません。 非常に詳しい解説をしていただきましてありがとうございます。 おかげさまで疑問となって詰まっていたものが キレイさっぱり解けました。 本当にありがとうございました。

その他の回答 (1)

  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.1

これでもはしょりすぎで全然説明ができていないのですが、あまりにも長文になってしまったので一旦これでポストします。後は個別に補足・お礼と回答のやり取りでやっていけば良いかなと。 > 「オブジェクトを保存しているファイル > (あるいはそのストリーム)側」が「受信側」で > 「そのオブジェクトの読み出しを行っているプログラム側」が > 「受信側」という理解で正しいでしょうか? 恐らく最初の受信側は送信側の事でしょうが、中間ファイルとデシリアライザーが一対になるでしょうか? 送信者とは「シリアライザーでシリアライズを行った人」という意味で、受信者は「デシリアライザーでデシリアライズを行った人」です。 だって、シリアライズの目的はインスタンスの状態を保持してそれをいつか元に戻すという一連の処理なのですから、クラスの中身を何かにする処理と、何かからクラスに戻す処理が一対になるはずでしょう? で、それらの処理は、違うJavaVM上で動く事もありまして、その時クラスの情報はそれぞれのJavaVMが持っています。これが一致しなかったら一大事。 仮に、以下のようなエンティティBeanを考えてみましょう。 public HogeBean implements Serializable { private static final serialVersionUID = -1L; public int age; public String name; } このBeanをインスタンス化してシリアライズしましょう。ここでは、仮にシリアライズされるとXML文書の形式になる事とします。 <HogeBean serialVersionUID="-1"> <age>19</age> <name>Anmochi</name> </HogeBean> 今、これが「シリアライズされたインスタンス」ですね。これがストリームによってファイルに保存されたり、ネットワーク上に流されたりする訳です。これが送信側。 次に、デシリアライズして使える状態(インスタンス)に戻さないとせっかくシリアライズした意味がありません。受け手でデシリアライズしましょう。受信側です。これまた仮に、受信側のJavaVMにロードされたクラスHogeBeanが以下のようになっていたらどうでしょうか? public HogeBean implements Serializable { private static final serialVersionUID = -2L; public int age; public String firstname; public String familyname; } おお! 中身が全然違う! ドラクエで言えば「おお、勇者よ、型が合わないとは情けない。」くらいの勢いですよ。これだと、デシリアライズできません。クラスは設計図ですよね。ところが、シリアライズされたインスタンスは型情報を持っていないので(注:本当は持っています)、デシリアライズをうんせうんせとやった挙句に違う事が分かるわけです。これでは無駄にコストがかかる。この場合、どっちのクラス構造が誤りなのかは問題ではありません。一致しない事が問題なのです。なのでバージョンIDを変えておけばする一発で(不一致という事実が)分かるという訳ですね。 > serialVersionUIDというのは読み出したオブジ・・・・ 現在ではserialVersionUIDは無くても動作します。その時の動作は詳しく検証していませんが、ランダムな数値が選ばれるのでしょうかね。あるいは-1L? > 上記理解が正しい場合、serialVersionUIDというのは「1L」といった > 単純な値でも特に問題ないのでしょうか? 問題ないと思います。 > 自動で割り振る機能があるそうですが > これを利用するメリットは何でしょうか? 自分で考えなくて良い。 > シリアライズする場合、なぜSerializableインターフェースを > 載せなければならない仕様になっているのでしょうか? それは誤解で、Serializableインタフェースを実装しなくてもシリアライズは可能です。ソースを見てこのクラスがシリアライズ可能かどうか、という判断を、「人間は」すぐ行えます。ところが、コンピュータが判断すると、それはとてもコストがかかる処理になります。なので、コンピュータがif(hoge instanceOf Serializable)の一発で判断できるように、人間様がコンピュータに教えてあげるという訳で、コンピュータ側からみたら先ほどのinstanceOf以上でも以下でもないのです。なので、Serializableインタフェースを実装しシリアライズ不可能なクラス、というのも当然作れちゃう。 > 最初からすべてのクラスはシリアライズ可能にしておくと > 何か不都合があるのでしょうか? ロジックしか記述されていないクラスなど、そもそもシリアライズの必要がないクラスはシリアライズできなくしておく方が良いと個人的には思う。技術的には前述の通り理論上どんなクラスでもシリアライズは可能だが、シリアライズする必要が無い場合は明示的にシリアライズさせない仕組みを作っておく方が良いと思うよ。

kyonn2008
質問者

お礼

丁寧にひとつずつ回答いただきありがとうございます。 >> 「オブジェクトを保存しているファイル >> (あるいはそのストリーム)側」が「受信側」で >恐らく最初の受信側は送信側の事でしょうが ご推察の通り、先の「受信側」は「送信側」と書いたつもりでした。 誤記です。 大変申し訳ありません。 >>‥バージョンIDを変えておけばする一発で(不一致という事実が)分かるという訳ですね。 丁寧な回答をありがとうございます。 バージョンIDの使われ方がよくわかりました。 しかし回答を拝見させていただいているなかで新たな疑問が生まれました。 回答文中の受信側JavaVMにロードされたクラスHogeBeanは serialVersionUIDが「-2L」となっているので 違うバージョンであることがすぐわかるということですが、 これを「-1L」として、クラスの構造が異なる送信側と serialVersionUIDを同じにするとどうなるのでしょうか? >>それは誤解で、Serializableインタフェースを実装しなくてもシリアライズは可能です。 JavaDocには 「クラスの直列化可能性は、java.io.Serializable インタフェースを実装したクラスによって有効になります。このインタフェースを実装していないクラスでは、その状態が直列化または直列化復元されることはありません。」 とあるのですが、anmochi様がおっしゃっている「インタフェースを実装しなくてもシリアライズは可能」というのは Javaという枠内の話ではなく、より一般的な「シリアライズ」というものを考えた場合の話でしょうか? >>Serializableインタフェースを実装しシリアライズ不可能なクラス、というのも当然作れちゃう。 上記と併せて、私の理解不足のためにこの部分もよく分かりませんでした。 JavaにおいてSerializableインタフェースを実装していながらシリアライズができないパターンというのは 具体的にどういうソースなのでしょうか? 教えてもらってばかりで大変恐縮ではありますが、 ご指導の程何卒よろしくお願い申し上げます。

関連するQ&A

  • serialVersionUID はどう利用する?

    表題のとおりなのですが、あるクラスをファイルとして保存するために、シリアライズするとありましたので、試してみました あるメーカーアプリを作り、そのファイルを生成。 別のクライアントアプリで、そのファイルを展開し利用。 と、活用したいのですが。 同じメーカーアプリケーション内ではちゃんと読み書きできるのですが、クライアントアプリ側ではひらいてくれずClassNotFoundExceptionが発生してしまいます。 型として制作しているクラスはそのまま同じクラスをクライアントアプリにもコピペして使ってるので、クラス名も内容も、serialVersionUID も同じ数字になってるのですが、 この場合なにが問題なのでしょうか。 そしてこのserialVersionUID は何の意味があるんでしょうか、いろいろその意味を検索して読んでみたのですが、それらが何を言ってるのか理解できません;

  • AndroidにおけるPathのシリアライズ化

    Androidで描いたPathをシリアライズ化して、サーバに送信してみたのですが java.io.NotSerializableException: android.graphics.Path このように、シリアライズできないという旨のエラーが出ました。 シリアライズできないオブジェクトは、どのようにしてシリアライズすればいいのでしょうか。 また、AndroidのPathのシリアライズ化に関して下記のページが見つかったのですが、英語があんまり読めなくて理解ができません。 http://stackoverflow.com/questions/4919740/how-to-serialize-an-object-of-android-graphics-path SerializablePathというクラスを作って、それを利用すればいいと思うのですが 具体的な使い方が分かりません。 それと、サーバへはArrayList<Path>の形で送信したいと思っています。

  • クラスの直列化に関して

    こんばんは。 現在、Strutsを使ったシステムをメンテナンスしているのですが、 java.io.Serializableを実装したクラスをアクションフォームBeanに しています。(全画面共通フォームBean) 私はまだ初心者なので、ActionFormを継承したクラスをアクションフォームBeanとしてしか使ったことがないので、 なぜ、直列化にし、さらに共通で使っているのかが分かりません・・・ 聞いたのですが、皆よく分からないとのことでした。 もしかして、直列化にすることは普通なのですか? また、直列化も調べたのですが、あまり理解できなかったので、 分かりやすく教えて頂けませんでしょうか? ご存知の方、よろしくお願い致しますm(_ _)m

    • ベストアンサー
    • Java
  • Javaの配列について

    お世話になります。 Javaでは配列は基本型ではなくオブジェクト型(参照型)だということなのですが(実際equals()やtoString()などを持っている)、配列に他のクラスやインターフェイスを継承させる方法はあるのでしょうか?例えば配列にSerializableをimplementsさせて、他のクラスのインスタンスのように直接ファイルに読み書きできるようにすることは、可能なのでしょうか? よろしくご教授ください。

    • ベストアンサー
    • Java
  • VC6++ char配列の文字列をシリアライズする方法

    入門書には、char配列の文字列をシリアライズで保存する場合は、CStringにキャストして保存するとあったのですが、保存時は ar << (CString)m_char; で保存されているようなのですが、読み出し時はどうすればいいのでしょうか? ar >> (CString)m_char; では読めませんでした。 VC初心者です。よろしくお願いします。

    • ベストアンサー
    • CGI
  • デシリアライズでオブジェクトを正常に復元できない。

    お世話になっております。 現在、シリアライズとデシリアライズの勉強をしているのですが、 デシリアライズの方が正常に行えないという状況に陥っています。 起こっている具体的な現象なのですが、 シリアライズ自体は問題無く行え、ファイルも作成されているのですが、 デシリアライズの段で例外はスローされずに表向き正常にデシリアライズ処理が走っているにも関わらず、 どうも正しく復元されていないのか、 復元されたはずのフィールドが参照するオブジェクトの内容を出力しようとしても、 nullが表示されてしまうという事が起きています。 尚、シリアライズ時には参照先の値が存在していた事はシリアライズと同時に シリアライズ元となるオブジェクトの値を標準出力して確認してあります。 (シリアライズで作成されたファイルの中身の検証を行ったわけではないので、 シリアライズの時点で既に正しい実行では無い可能性があるかもしれませんが) 何故うまくいかないのか調べていましたが解明できずにいます。 どうかお知恵を貸していただきたいです。 ソースを記載すると文字数制限を超えてしまいますので、 以下に今回の問題となっている挙動を示すソースのURLを記載します。 ※全てのソースはパッケージtoolsの中に含まれています。 ※ファイルはカレントディレクトリ以下のserializeフォルダに配置するようにしています。 http://13.pro.tok2.com/~dabun/tools/RecordMap.java http://13.pro.tok2.com/~dabun/tools/Record.java http://13.pro.tok2.com/~dabun/tools/WriteMain.java http://13.pro.tok2.com/~dabun/tools/ReadMain.java <ソース補足> ・RecordMap.java(HashMapのフィールドにInnerRecordクラス以下のオブジェクトを保持するクラス) ・Record.java(RecordMapの内部クラスInnerRecordの外部公開用インターフェース) ・WriteMain.java(mainメソッドを含む。シリアライズ検証用クラス) ・ReadMain.java(mainメソッドを含む。デシリアライズ検証用クラス) 以上です。よろしくお願いします。

    • ベストアンサー
    • Java
  • ヤフーメール(web)の質問

    ヤフーメールをwebメールとして使う場合、送信メールの保存が出来ますが、どのくらいの容量まで保存できるのでしょうか?(メールボックス自体6MBは理解しています) 要は、受信メールと、送信済みメールも合計が、6MBまで保存できるということでしょうか? あと、メールが6MBになったとき、どうなるのでしょうか? 新しいメールが受信できないのは、理解出来ます。 その場合、自分で、受信メールなり、送信メールなり、削除しないといけないのでしょうか? 要は、携帯の場合、メールボックスがいっぱいになると、古いメールから、自動で削除されまうすが、webメールの場合は、どうなるのかと思いまして。

  • iPhoneのIMAPのメールをローカルに送信、受信共にすべて保存した

    iPhoneのIMAPのメールをローカルに送信、受信共にすべて保存したい。 iphoneのIMAPのメールをThunderbirdで管理してるのですが、受信メールは、1分毎に受信してフィルタをかけて、ローカルのフォルダに保存しております。 が、送信メールはThunderbirdからメール送信した場合にしかフィルタが適用されません。 iPhoneから送信したメールをThunderbirdで同期して、定期的に(例えば1分毎に)かつ自動でローカルに保存する方法はないでしょうか? iPhone側で削除しても、Thunderbird側ですべての送信、受信メールがローカルに保存されるようにしたいのです。 よろしくお願いいたします。

  • JAVAのクラスの考え方は・・?

    JAVAの勉強をしていている学生です。 常々思っていたのですが、クラスの考え方がしっくりきてませんヽ(~-~ よく参考書などで書かれていることで 「クラスは設計図のようなもの、オブジェクトはそこから作成した実体」 「鋳型がクラスでどんどん作れるのがインスタンス」 といった話が疑問でならないのです。 というのも・・クラスの設計って、自分自身をフィールドに宣言したりできますよね。。 でそこから生成して、また自分自身のフィールドに生成して・・とか。 インターフェースを実装したクラスで、、、内部クラスを持ったクラスで、、、ジェネリッククラス、、。 となってくると、最初の考え方では、論理的に無理?私の脳内では変換しきれないです(´;ω;) 多分前提となる考え方が間違っていたり、私の想像力が乏しいだけだと思います。 どなたか、「クラスってこう考えればオブジェクト指向が見えてくる」と表現している本やサイトなどご存じないでしょうか。 一朝一夕で理解しようとは思っていませんので、きちんと参考にして理解しようと頑張ります! 「私的には・・」や「あなたが勘違いしている箇所は・・」といったご意見もぜひお聞きしたいです! クラスかオブジェクト指向かどっちかというより、クラスありきでJAVAのオブジェクト指向が本当に理解できると考えています。参考書やWEBを探してみた限りではやっぱり理解できないです(´;ω;) ちなみにC言語を中学生で始め、プログラミングに触れました。

  • ワイヤレスモニター 何が必要?

    PCでワイヤレスモニター使いたいです。HDMI端子はあります。 18000円 送信側と受信側の2つ要るのは理解できました。 受信側だけの製品はやすいです。 2000円程度 送信側ってそんなに高いんでしょうか?

専門家に質問してみよう