なぜJavaはSerializableインターフェースを必要とするのですか?


114

シリアライゼーションにはかなりの労力を費やしていますが、使用するすべてのオブジェクトにSerializableタグを指定しなければならないのは、ちょっとした負担です。特にそれが私たちが実際に変更することができないサードパーティのクラスである場合。

問題は次のとおりです。Serializableは空のインターフェイスであり、Javaは追加すると堅牢なシリアル化を提供する implements Serializableので、なぜそれらはすべてをシリアル化可能にしていないのですか?

何が欠けていますか?


独自のオブジェクトをSerializableにしたい場合はどうなりますか?それとも私は何かを誤解しましたか?
ジョーフィリップス

オブジェクトのすべてのフィールドをシリアル化可能にする必要があるため、NotSerializableExceptionは引き続き発生します
Yoni Roit

Pop Catalinとdmitryの「このシリアライズ可能なトリックは、10年か2年前に取られたもう1つの間違った決定に過ぎません」に完全に同意します。シリアライゼーションがどれほど危険かは問題ではありません。そして、宣言が明示的であるため、「特別な注意を払う必要があることを知っている」というのは真実ではありません。それを必要とするすべての人は、最初に「実装」のものを置き、次に何かがうまくいかなかった場合の影響について考えます。特殊なケースに適用するための「Unserializable」インターフェースを提供してくれれば、それはすべてより明確になったかもしれません。
ジャック

回答:


120

シリアライゼーションには落とし穴があります。このフォームの自動シリアル化サポートにより、クラスの内部はパブリックAPIの一部になります(そのため、javadocは永続化されたクラスのフォームを提供します)。

長期的な永続性のために、クラスはこのフォームをデコードできる必要があります。これにより、クラス設計に加えることができる変更が制限されます。これはカプセル化を壊します。

シリアライゼーションもセキュリティの問題につながる可能性があります。参照のあるオブジェクトをシリアル化できるようにすることで、クラスは(結果のバイトデータを解析して)通常はできないデータにアクセスできます。

他にも、内部クラスのシリアル化された形式が適切に定義されていないなどの問題があります。

すべてのクラスをシリアライズ可能にすると、これらの問題が悪化します。「Effective Java Second Edition」、特にItem 74:Implement Serializableを慎重にチェックしてください。


2
これは明らかに良い答えです。選択した答えがこれではないことに失望しています。投稿は「シリアライズ可能なものを宣言する必要があるのでイライラする」アジェンダを念頭に置いて選択されたようです。これは、過去に学んだセキュリティと設計のレッスンに注意を払わずに、完全に解放したい人の例です。
gbtimmon

@McDowell永続化された形式のクラスとはどういう意味ですか?私はそのリンクをたどりましたが、あなたの意味が理解できませんか?これについて説明してもらえますか?
オタク

@Geek - URLタイプの直列化された形式(例えば)タイプが持っている必要がありますプライベートどのようなフィールドを定義し、彼らがで宣言する必要があります注文する。
マクダウェル

@McDowellなぜ順序が重要なのですか?
オタク

12
@McDowellこんにちは。私は4年前のこの質問の元の投稿者です。何か意味がある場合は、あなたの回答を承認済みとして選択しました。私はあなたの答えは本当に良いものだと思います、そして私はおそらくそのようにそれを見るにはあまりにも未熟だったでしょう。今修正中:)
Yoni Roit、2013年

32

今回はJavaと.Netの両方の人々が間違っていたと思います。デフォルトですべてをシリアライズ可能にして、代わりに安全にシリアライズできないクラスをマークする必要があるだけの方がいいでしょう。

たとえば、Smalltalk(70年代に作成された言語)では、すべてのオブジェクトがデフォルトでシリアライズ可能です。オブジェクトの大部分がシリアル化しても安全であり、そのうちのいくつかはそうでないという事実を考えると、これがJavaに当てはまらない理由はわかりません。

オブジェクトを(インターフェースで)シリアライズ可能としてマークしても、そのオブジェクトは魔法のようにシリアライズ可能ではありません。それはずっとシリアライズ可能でした。システムが独自に見つけたものを表現しただけなので、本当の理由はありませんシリアライゼーションは現在の方法です。

設計者が下した決定の悪さか、シリアル化が後付けだったのか、プラットフォームがすべてのオブジェクトに対してデフォルトで安全かつ一貫してシリアル化する準備ができていなかったと思います。


26
クラスを設計および実装するときは、インスタンスが適切な方法でシリアル化されるように、特別な注意を払う必要があります。シリアライズ可能なインターフェースとは、実際には「プログラマーとして、シリアライゼーションの結果を理解し、JVMがこれをシリアライズできるようにした」
Rolf Rander

@Rolf Rander:ほとんどの場合、まったく気にする必要はありません。クラスを直列化可能としてマークしてください。シリアル化は、すべてのdefaulによりONされているだろう場合は...クラスの直列化可能を作るために行うには自然なものだっただろう、すべての開発者の考え方があまりにも違っていただろうオブジェクト
ポップカタリン

たとえば、メモリリークがないことを確認するなど、優れたクラス設計のリストに別の懸念が追加されます。それでも、優れたクラス設計では、可能な場合はクラスをシリアル化できることがますます必要になります。
ポップカタリン

3
@StaxManは、後でクラスをシリアル化する必要があるができないことを認識しているため、非常にコストがかかる可能性があります。余計な労力がほとんどかからないケースの1つです。あなたはライブラリを書いているし、他の誰かがソースコードなしで、それが消費されます場合、これは特にそうです
ポップカタリンを

2
私はこの答えに完全に同意します。多くの言語では、すべてがデフォルトでシリアライズ可能です。そして、実際にはJVMと同じです。Reflectionを使用して、プライベートかどうかにかかわらず、クラスメンバーにアクセスするのは簡単です。このSerializableトリックは、10年または2年前に行われたもう1つの間違った決定であり、標準ライブラリのコレクションおよび文字列処理の欠陥など、純粋なJavaを処理する際の煩わしさをさらに1つ増やします。幸いにもKryoがありますが、依存関係であり、最初にそれを見つける必要があります。これは、組み込みのシリアル化が行われる方法です。
ドミトリー2014

20

すべてが真にシリアル化可能であるとは限りません。たとえば、ネットワークソケット接続を考えてみます。ソケットオブジェクトのデータ/状態をシリアル化できますが、アクティブな接続の本質は失われます。


これは私の問題です。ソケットをシリアル化しようとするほど賢くなければ、デバッグ中にエラーが発生します。ただし、サードパーティのクラスがSerializableを実装していないため、Javaシリアル化をまったく使用できない状況になっています。
Yoni Roit、

4
このケースを処理するには、いくつかの適切な方法があります。たとえば、サードパーティクラスのキーデータを読み書きする方法を知っているSerializableラッパークラスを作成します。ラップされたインスタンスを一時的にして、writeObjectとreadObjectをオーバーライドします。
グレッグケース

APIの必要なオブジェクトから継承して、それらのクラスをシリアル化できますか?
Joel Coehoorn、2009年

@ジョエル:それは良いアイデアですが、それでもハックです。私はこのすべてが別のトレードオフが間違っていたと思います。コメントしてくれてありがとう。
Yoni Roit、

1
これは、私たちが本当に必要なのはimplements NotSerializable:)
Rob Grantの

13

JavaでのSerializableの主な役割は、デフォルトで、他のすべてのオブジェクトを実際には非直列化できるようにすることです。シリアライゼーションは、特にデフォルトの実装では、非常に危険なメカニズムです。したがって、C ++の友情と同様に、シリアライズ可能にするのに少しコストがかかっても、デフォルトではオフになっています。

構造の互換性は保証されていないため、シリアライゼーションは制約と潜在的な問題を追加します。デフォルトではオフになっているのが良いです。

私は、標準のシリアル化が私が望んでいることを行う重要なクラスをほとんど見たことがないことを認めなければなりません。特に複雑なデータ構造の場合。したがって、クラスをシリアライズ可能にするために費やす労力は、インターフェースを追加するコストに相当します。


9

一部のクラス、特にファイル、ソケット、スレッド、またはDB接続などのより物理的なクラスを表すクラスでは、インスタンスをシリアル化してもまったく意味がありません。他の多くの場合、シリアライゼーションは一意性の制約を破壊するか、クラスの異なるバージョンのインスタンスを処理するように強制するだけなので、望ましくない可能性があるため、問題が発生する可能性があります。

間違いなく、デフォルトですべてをシリアライズ可能にし、キーワードまたはマーカーインターフェイスを介してクラスをシリアライズ不可能にする方が良いかもしれませんが、そのオプションを使用する必要がある人はおそらくそれについて考えないでしょう。それがそうであるように、Serializableを実装する必要がある場合は、例外によってそのことが通知されます。


4

ただし、プログラマとして、オブジェクトがシリアル化されることを確認する必要があったと思います。



1

特定のクラスのインスタンスがSerializableであることを明示的に述べる必要がある場合、言語はそれを許可する必要があるかどうかについて考えることを強いられます。単純な値オブジェクトの場合、シリアル化は簡単ですが、より複雑なケースでは、物事をじっくりと考える必要があります。

JVMの標準のシリアル化サポートに依存するだけで、あらゆる種類の厄介なバージョン管理の問題にさらされることになります。

一意性、「実際の」リソースへの参照、タイマー、および他の多くのタイプのアーティファクトは、シリアル化の候補ではありません。


1

これを読んで、Serializable Interfaceを理解し、なぜいくつかのクラスだけをSerializableにする必要があるのか​​を理解します。また、ストアドプロシージャからいくつかのフィールドを削除する場合に備えて、transientキーワードをどこで使用するかについて注意する必要があります。

http://www.codingeek.com/java/io/object-streams-serialization-deserialization-java-example-serializable-interface/


0

まあ、私の答えは、これは正当な理由がないということです。そして、あなたのコメントから、あなたはすでにそれを学んだことがわかります。他の言語は、10に数えた後、ツリーにジャンプしないすべてのものを喜んでシリアライズしようとします。オブジェクトはデフォルトでシリアライズ可能である必要があります。

したがって、基本的に必要なことは、サードパーティクラスのすべてのプロパティを自分で読み取ることです。または、それが選択肢である場合は、逆コンパイルし、damnキーワードをそこに置いて、再コンパイルします。


2
構造の互換性が保証されていないため、シリアライゼーションは制約と潜在的な問題を追加します。私見、それがデフォルトでオフになっているのは良いことです。
Uri

「構造の互換性」の意味がわかりません。
nes1983

0

Javaには、ランタイム固有であるため単純にシリアライズできないものがあります。ストリーム、スレッド、ランタイムなどのようなもの、および一部のGUIクラス(基盤となるOSに接続されているもの)でさえ、シリアル化できません。


0

ここで他の回答で述べた点に同意しますが、実際の問題は逆シリアル化にあります。クラス定義が変更されると、逆シリアル化が機能しないという実際のリスクがあります。既存のフィールドを変更しないことは、ライブラリの作成者が作成するかなり重要な取り組みです!APIの互換性を維持することは、現状では十分な作業です。


これは正しくありません。オブジェクト直列化仕様の直列化可能オブジェクトバージョン管理の章を読む必要があります。これは、ここで主張することが真実である場合には存在しません。クラス定義は、以前のシリアル化と互換性がなくなる前に、かなり広い範囲で変更できます。そして、それは確かに質問への答えではありません。本当の理由は、セキュリティ上の懸念に関係しています。
ローンの侯爵2013年

@EJP、私はあなたのポイントを反映するために正直さのために私の回答を編集しました。しかし、感情は立っている、それは間違いなくオプトアウトではなくオプトインであるべき大きなコミットメントです
CurtainDog

0

ファイルまたは他のメディアに永続化する必要があるクラスは、Serializableインターフェースを実装して、JVMがクラスオブジェクトをシリアル化できるようにする必要があります。ObjectOutputStreamを使用する場合にのみすべてのJVMがクラスをシリアル化した後、オブジェクトクラスがシリアル化されない理由は、どのクラスもインターフェイスを実装する必要がないということです。

クラスのバージョンが大きな問題であるにもかかわらず、Objectクラスがデフォルトでシリアル化できない理由。したがって、シリアライゼーションに関係する各クラスは、明示的にSerializableとしてマークし、バージョン番号serialVersionUIDを提供する必要があります。

serialVersionUIDが指定されていない場合、オブジェクトのデシリアライズ中に予期しない結果が発生します。そのため、serialVersionUID が一致しない場合、JVMはInvalidClassExceptionをスローします。したがって、すべてのクラスはSerializableインターフェースを実装し、serialVersionUIDを提供して、両端に表示されるクラスが同一であることを確認する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.