私たちはシリアライゼーションに重点を置いており、使用するすべてのオブジェクトでSerializableタグを指定する必要があるのは、一種の負担です。特に、サードパーティクラスの場合、実際に変更することはできません。
問題は、Serializableは空のインターフェースであり、Javaはimplements Serializable
-なぜ彼らはすべてを直列化可能にしなかったのですか?
私は何が欠けていますか?
シリアル化には落とし穴がたくさんあります。この形式の自動シリアル化サポートにより、クラス内部がパブリックAPIの一部になります(これが、javadocが クラスの永続形式 を提供する理由です)。
長期的な永続性を確保するには、クラスでこのフォームをデコードできる必要があります。これにより、クラス設計に加えることができる変更が制限されます。これはカプセル化を破壊します。
シリアル化は、セキュリティの問題にもつながる可能性があります。参照を持つオブジェクトをシリアル化できることにより、クラスは(結果のバイトデータを解析することで)通常はアクセスできないデータにアクセスできます。
内部クラスのシリアル化形式が適切に定義されていないなど、他の問題もあります。
すべてのクラスをシリアル化可能にすると、これらの問題が悪化します。 有効Java Second Edition 、特に項目74:Serializableを慎重に実装します)。
Javaと.Netの人々は今回は間違っていたので、デフォルトですべてをシリアル化可能にし、代わりに安全にシリアル化できないクラスのみをマークする必要があると思います。
たとえば、Smalltalk(70年代に作成された言語)では、デフォルトですべてのオブジェクトがシリアル化可能です。大多数のオブジェクトは安全にシリアライズでき、そのうちのいくつかはそうではないという事実を考えると、なぜJavaでこれが当てはまらないのか分かりません。
オブジェクトをシリアル化可能として(インターフェースを使用して)マークしても、そのオブジェクトが魔法のようにシリアル化可能になるわけではありませんずっとシリアル化可能だったシリアル化が今のようになっている理由はありません。
設計者が下した決定が下手だったか、シリアル化が後から考えられたか、プラットフォームがすべてのオブジェクトをデフォルトで安全かつ一貫してシリアル化する準備ができていなかったと思います。
すべてが真にシリアル化できるわけではありません。たとえば、ネットワークソケット接続を使用します。ソケットオブジェクトのデータ/状態をシリアル化できますが、アクティブな接続の本質は失われます。
JavaでのSerializableの主な役割は、デフォルトで他のすべてのオブジェクトを実際に非シリアライズ可能にすることです。特にデフォルト実装では、シリアライゼーションは非常に危険なメカニズムです。ものをシリアライズ可能にするのに少し費用がかかっても、デフォルトではオフになっています。
構造化の互換性が保証されていないため、シリアル化は制約と潜在的な問題を追加します。デフォルトでオフになっているのは良いことです。
私は、標準のシリアル化が私が望んでいることを行う非常に少数の重要なクラスを見たことを認めなければなりません。特に複雑なデータ構造の場合。したがって、クラスを直列化できるようにするために費やす労力は、インターフェースを追加するコストを大幅に削減します。
一部のクラス、特にファイル、ソケット、スレッド、DB接続などのより物理的なものを表すクラスの場合、インスタンスをシリアル化することはまったく意味がありません。他の多くの人にとって、直列化は一意性の制約を破壊するか、単にクラスの異なるバージョンのインスタンスを処理するように強制するため、問題になる場合がありますが、これは望ましくありません。
おそらく、デフォルトですべてをシリアライズ可能にし、キーワードまたはマーカーインターフェイスを介してクラスを非シリアライズ可能にした方が良いかもしれませんが、そのオプションを使用する人はおそらくそれを考えないでしょう。方法は、Serializableを実装する必要がある場合、例外によって通知されます。
プログラマーとして、あなたのオブジェクトがシリアル化されることを確実にするためだったと思います。
どうやら、いくつかの予備設計ではすべてがシリアル化可能でしたが、セキュリティと正確性の懸念から、最終設計は誰もが知っているようになりました。
ソース: ObjectOutputStreamに書き込むためにクラスがSerializableを実装する必要がある理由 。
特定のクラスのインスタンスが直列化可能であることを明示的に述べる必要があるため、言語では、それを許可する必要があるかどうかを検討する必要があります。単純な値オブジェクトのシリアル化は簡単ですが、より複雑なケースでは、本当に考え抜く必要があります。
JVMの標準シリアル化サポートに依存するだけで、あらゆる種類の厄介なバージョン管理の問題にさらされます。
一意性、「実際の」リソースへの参照、タイマー、その他多くの種類のアーティファクトは、シリアル化の候補ではありません。
これを読んでSerializable Interfaceを理解し、なぜSerializableを少数のクラスのみにする必要があるのかを理解し、また、ストアドプロシージャから少数のフィールドを削除する場合に一時的なキーワードを使用する場所に注意を払ってください。
まあ、私の答えは、これは正当な理由がないということです。そして、あなたのコメントから、私はあなたがすでにそれを学んだことを見ることができます。他の言語では、10にカウントした後、ツリーにジャンプしないすべてのものを喜んでシリアル化しようとします。オブジェクトはデフォルトでシリアル化可能になっている必要があります。
したがって、基本的に必要なことは、サードパーティクラスのすべてのプロパティを自分で読み取ることです。または、それがあなたのためのオプションであるならば:逆コンパイルして、いまいましいキーワードをそこに置いて、そして再コンパイルしてください。
ここでの他の回答で指摘された点には同意しますが、本当の問題は逆シリアル化にあります。クラス定義が変更された場合、逆シリアル化が機能しない本当のリスクがあります。既存のフィールドを変更しないことは、ライブラリの作成者にとって非常に大きなコミットメントです! APIの互換性を維持するのは、面倒なことです。
Javaには、ランタイム固有であるため単純にシリアル化できないものがあります。ストリーム、スレッド、ランタイムなど、さらには基礎となるOSに接続されているGUIクラスなど)シリアル化できません。
JVMがクラスオブジェクトをシリアル化できるように、ファイルまたは他のメディアに永続化する必要があるクラスはSerializableインターフェイスを実装する必要があります。 Objectクラスがシリアル化されないのであれば、すべてのJVMがObjectOutputStreamを使用する場合にのみクラスをシリアル化するため、インターフェースを実装する必要はありません。 。
クラスバージョンが主要な問題であるという事実において、Objectクラスがデフォルトでシリアル化できない理由。したがって、シリアル化に関心のある各クラスは、明示的にSerializableとしてマークされ、バージョン番号serialVersionUIDを提供する必要があります。
serialVersionUIDが指定されていない場合、オブジェクトのデシリアライズ中に予期しない結果が得られるため、JVMはInvalidClassException if serialVersionUIDが一致しない場合にスローします。したがって、すべてのクラスはSerializableインターフェースを実装し、serialVersionUIDを提供して、両端で提示されるクラスが同一であることを確認する必要があります。