0

を拡張ArrayList<B> arrayする特定のクラスのオブジェクトがあるとします。インスタンス フィールドとフィールドがあります。を使用して.datファイルに保存するには、 (だけでなく!)実装が必要であることを知っています。ただし、ファイルからオブジェクトをロードするときに(を使用して)次のことがわかりました。BABbbAaaarrayObjectOutputStreamBArrayListSerializableObjectInputStream

 arrayLoaded = (ArrayList<B>)myObjIn.readObject();

ロードされた配列は元の配列と同一ではありません: 特定のケースでarrayLoaded.get(0).bbは、 は と同じ値を持ちますが、arrayarrayLoaded.get(0).aaゼロ化」されています。arrayファイルに保存されたときの値に関係なく、デフォルトの初期化値があります。しかし、この問題は もA実装させることで解決されSerializableます。

私を悩ませているのは、このエラーが非常に微妙であることです: 例外も警告も (Eclipse では) も何もありません。これには理由がありますか、それとも単に Java 開発者による見落としですか? Serializableオブジェクト IO ストリームを使用するたびに、それを受け入れて、階層内のどのクラスが実装されているかをよく考える必要がありますか?

4

2 に答える 2

2

Bを実装しているからSerializableといって、シリアル化されるものにシリアル化できないスーパークラスのフィールドがさかのぼって含まれることはありません。Serializable(これは、特に、クラスを拡張して実装するだけで、任意のクラスのプライベートフィールドとパッケージプライベートフィールドをシリアル化できると、カプセル化に違反することを考えると、理にかなっています。)

で宣言さAれたフィールドは、で宣言されたフィールドと同じように動作transientBます。ただし、回避策があります。のドキュメントからSerializable

シリアル化できないクラスのサブタイプをシリアル化できるようにするために、サブタイプは、スーパータイプのパブリック、保護、および(アクセス可能な場合)パッケージフィールドの状態を保存および復元する責任を負う場合があります。サブタイプがこの責任を負うのは、サブタイプが拡張するクラスに、クラスの状態を初期化するためのアクセス可能な引数なしのコンストラクターがある場合のみです。

したがって、のシリアル化/逆シリアル化を処理するwriteObjectために実装readObjectする必要があります。BA.aa

于 2013-01-20T01:47:13.810 に答える
2

私を悩ませているのは、このエラーが非常に微妙であることです: 例外も警告も (Eclipse で) も何もありません。これには理由がありますか、それとも単に Java 開発者による見落としですか?

これは設計によるものです。(@Paul Belloraの回答を参照)。代替手段は次のとおりです。

  • スーパークラスが Serializable でない限り、Serializable クラスを宣言することを違法にします。それは明らかに実行不可能です。

  • スーパークラス フィールドを自動的にシリアル化します。これは、シリアル化する必要がある場合、またはシリアル化できない場合に壊れます。transient(スーパークラスの設計者がシリアライズ可能にするつもりがなかった場合、フィールドにラベルを付けていないため、ここでは当てにならないことに注意してください。)

オブジェクト IO ストリームを使用するたびに、それを受け入れて、階層内のどのクラスが Serializable を実装しているかをよく考える必要がありますか?

基本的に、はい。特に、シリアライズ可能でない既存のクラスのシリアライズ可能サブクラスを作成する場合は、よく考える必要があります。

FindBugs / PMD / etc ルールを記述して、この特定の使用法に問題がある可能性があることを示すフラグを立てることは可能だと思います。

于 2013-01-20T03:22:32.663 に答える