jdk 1.5 と 1.6 (Java 6) のオブジェクトのシリアライズ (双方向通信) を混在させても安全かどうか疑問に思っています。私はこの質問に関する太陽からの明示的な声明を探しましたが、成功しませんでした. したがって、技術的な実現可能性に加えて、問題に関する「公式の」声明を探しています。
8 に答える
シリアル化メカニズム自体は変更されていません。個々のクラスについては、特定のクラスによって異なります。クラスに serialVersionUID フィールドがある場合、これはシリアライゼーションの互換性を示すと想定されています。
何かのようなもの:
private static final long serialVersionUID = 8683452581122892189L;
変更されていない場合、シリアル化されたバージョンは互換性があります。JDK クラスの場合、これは保証されていますが、重大な変更を行った後に serialVersionUID を更新するのを忘れる可能性は常にあります。
JDK クラスの互換性が保証されていない場合、これは通常 Javadoc に記載されています。
警告: このクラスのシリアライズされたオブジェクトは、将来の Swing リリースと互換性がありません
1.5と1.6のシリアル化メカニズムは互換性があります。したがって、1.5および1.6コンテキストでコンパイル/実行された同じコードは、シリアル化されたオブジェクトを交換できます。2つのVMインスタンスが同じ/互換性のあるバージョンのクラスを持っているかどうか(serialVersionUIDフィールドで示される場合があります)は、JDKのバージョンとは関係のない別の質問です。
シリアル化可能なFoo.javaが1つあり、これを1.5および1.6 JDK / VMで使用する場合、1つのVによって作成されたFooのシリアル化されたインスタンス。他の人が逆シリアル化することができます。
Java 1.5 プログラムで ObjectOutputStream を使用してファイルに書き込まれたシリアル化されたオブジェクトでテストした後、Java 1.6 プログラムで ObjectInputStream を使用して読み取りを実行した後、これは問題なく機能したと言えます。
クラスを変更することは可能ですが、serialVersionUID を変更するのを忘れることは可能です。したがって、「クラスが serialVersionUID を定義し、これが変更されない場合、そのクラスは互換性があることが保証されている」というのは正しくありません。むしろ、同じ serialVersionUID を持つことが、API が後方互換性を約束する方法です。
特に明記しない限り、これはバイナリ互換性の一部です。Swing クラスは、明らかにバージョン間で互換性がありません。他のクラスで問題を見つけた場合は、bugs.sun.comでバグを報告してください。
Java Object Serialization Specificationを読みましたか? バージョン管理に関するトピックがあります。クラス実装者向けの記事もあります: Discover the secret of the Java Serialization API . Java の各リリースには、互換性に関する注意事項が付属しています。
シリアライゼーションに関する Java 6 仕様から:
目標は次のとおりです。
- 次の方法で、異なる仮想マシンで動作するクラスの異なるバージョン間の双方向通信をサポートします。
- JavaTM クラスが、同じクラスの古いバージョンによって書き込まれたストリームを読み取れるようにするメカニズムを定義します。
- JavaTM クラスが、同じクラスの古いバージョンによって読み取られることを意図したストリームを書き込めるようにするメカニズムを定義する。
- 永続性と RMI のデフォルトのシリアル化を提供します。
- RMI がシリアライゼーションを使用できるように、単純なケースで適切に実行し、コンパクトなストリームを生成します。
- ストリームの書き込みに使用されたクラスと正確に一致するクラスを識別してロードできる。
- バージョン管理されていないクラスのオーバーヘッドを低く抑えます。
- ストリームに保存されたオブジェクトに固有のメソッドを呼び出さなくても、ストリームを走査できるストリーム形式を使用します。
Java 1.5 と 1.6 を混在させるのは安全ではありません。たとえば、ファイルにシリアル化された Java 1.5 オブジェクトがあり、それを Java 1.6 で開こうとしましたが、以下のエラーが発生しました。
java.io.InvalidClassException: javax.swing.JComponent; local class incompatible: stream classdesc serialVersionUID = 7917968344860800289, local class serialVersionUID = -1030230214076481435
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readArray(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readArray(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
Java Beans 仕様では、強力な下位互換性を可能にする、バージョンに依存しないシリアライゼーション メソッドが詳述されていることに注意してください。また、読み取り可能な「シリアル化された」フォームになります。実際、シリアライズされたオブジェクトは、メカニズムを使用して非常に簡単に作成できます。
XMLEncoder
およびXMLDecoder
クラスのドキュメントを参照してください。
オブジェクトをネットワーク経由で渡すために必ずしもこれを使用するわけではありませんが (ただし、高いパフォーマンスが必要な場合はシリアル化も使用しません)、永続的なオブジェクト ストレージには非常に役立ちます。