8

次のようなオブジェクトがあります。

    public class Records implements java.io.Serializable{
        private int cId;
        private int pId;
        private int vlaue;
        private int tag;

        public Records(int c, int p, int v, int t){
                this.cId=c;
                this.pId=p;
                this.value=v;
                this.tag=t;
        }
}

大量のデータを収集し、上記のクラスのようにオブジェクトを構築し、それらをディスクにシリアライズしました。

クラス ファイルに含めるのを忘れていたダンプの 1 つに、各オブジェクトの値にアクセスするメソッドがあります。たとえば、特定のオブジェクトの cId 値にアクセスします。

このようなメソッドを追加するためにクラス定義を変更しましたが、オブジェクトを Records クラスに逆シリアル化できず、次のランタイム エラーが発生しました。

java.io.InvalidClassException: Records; local class incompatible: stream classdesc serialVersionUID = -1232612718276774474, local class serialVersionUID = -8244963718951538904
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:579)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1749)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1346)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)
    at DeSerialise.main(DeSerialise.java:21)

Javaにそれらが同じ定義であることを伝え、serialVersionUIDを変更する必要があると思いますが、どうすればよいかわかりませんか? どんなアイデアでも大歓迎です!

4

4 に答える 4

9

クラスに以下を追加してみてください。

private static final long serialVersionUID = -1232612718276774474L;

これにより、クラスserialVersionUIDは、インスタンスがシリアル化されたときに使用されたコンパイラによって生成された値と一致します。

ドキュメントからの次の引用は読む価値があります(私の強調):

シリアル化ランタイムは、シリアル化されたオブジェクトの送信者と受信者がシリアル化に関して互換性のあるそのオブジェクトのクラスをロードしたことを確認するために逆シリアル化中に使用される、serialVersionUIDと呼ばれるバージョン番号を各シリアル化可能なクラスに関連付けます。受信者が、対応する送信者のクラスとは異なるserialVersionUIDを持つオブジェクトのクラスをロードした場合、逆シリアル化すると、InvalidClassExceptionが発生します。シリアル化可能なクラスは、静的、final、およびタイプがlongである必要がある「serialVersionUID」という名前のフィールドを宣言することにより、独自のserialVersionUIDを明示的に宣言できます。

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

シリアル化可能なクラスがserialVersionUIDを明示的に宣言していない場合、シリアル化ランタイムは、Java(TM)オブジェクトのシリアル化仕様で説明されているように、クラスのさまざまな側面に基づいて、そのクラスのデフォルトのserialVersionUID値を計算します。ただし、デフォルトのserialVersionUID計算は、コンパイラの実装によって異なる可能性のあるクラスの詳細に非常に敏感であり、逆シリアル化中に予期しないInvalidClassExceptionsが発生する可能性があるため、すべてのシリアル化可能なクラスで明示的にserialVersionUID値を宣言することを強くお勧めします。したがって、さまざまなJavaコンパイラ実装間で一貫したserialVersionUID値を保証するには、シリアライズ可能なクラスで明示的なserialVersionUID値を宣言する必要があります。また、明示的なserialVersionUID宣言では、可能な場合はプライベート修飾子を使用することを強くお勧めします。このような宣言は、すぐに宣言するクラスにのみ適用されるためです。serialVersionUIDフィールドは、継承されたメンバーとしては役立ちません。配列クラスは明示的なserialVersionUIDを宣言できないため、常にデフォルトの計算値がありますが、配列クラスの場合、serialVersionUID値を一致させる必要はありません。

于 2013-01-24T15:02:27.743 に答える
0

次のように、クラスでシリアルバージョンIDを宣言できます。

private static final long serialVersionUID = -1232612718276774474L;
于 2013-01-24T15:03:17.160 に答える
0

はい、クラスに serialversionId を指定することが非常に重要です。そうしないと、シリアル化されたクラスを識別するのが難しくなります。

古いシリアル化されたオブジェクトを使用する代わりに、新しいシリアル化されたオブジェクトを作成することもできます。

Eclipse IDE は自動的に serialversionId を生成しますので、それを使用してみてください。

于 2013-01-24T15:05:16.743 に答える
0

The problem is that you serialized data without having a serialVersionUID defined in your class. Adding setters and getters is ok and does not impact serialization, but the compiler might generate another UID when you recompile the class which will lead to an exception when you try to deserialize your data. If need to actually deserialize the data you serialized using the first version of your class you will need to know what UID was generated by the compiler the first time: this can be seen in the error message, so you need to set serialVersionUID to -1232612718276774474L.

于 2013-01-24T15:10:13.880 に答える