72

Java では、クラスが Serializable を実装しているが抽象的である場合、serialVersionUID long を宣言する必要がありますか、それともサブクラスはそれのみを必要としますか?

この場合、型の目的は RMI 呼び出しで使用されるため、すべてのサブクラスがシリアライゼーションを処理するという意図があります。

4

4 に答える 4

52

serialVersionUIDは、脱気化されたオブジェクトとクラスの現在のバージョンとの間の互換性を判断するために提供されています。 そのため、クラスの最初のバージョン、この場合は抽象基本クラスでは実際には必要ありません。その抽象クラスのインスタンスをシリアル化/逆シリアル化することは決してないので、serialVersionUIDは必要ありません。

(もちろん、それはあなたが取り除きたいコンパイラ警告を生成しますよね?)

ジェームズのコメントは正しいことがわかりました。抽象基本クラスのserialVersionUIDは、サブクラスに伝播されます。これに照らして、基本クラスにserialVersionUIDが必要です

テストするコード:

import java.io.Serializable;

public abstract class Base implements Serializable {

    private int x = 0;
    private int y = 0;

    private static final long serialVersionUID = 1L;

    public String toString()
    {
        return "Base X: " + x + ", Base Y: " + y;
    }
}



import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Sub extends Base {

    private int z = 0;

    private static final long serialVersionUID = 1000L;

    public String toString()
    {
        return super.toString() + ", Sub Z: " + z;
    }

    public static void main(String[] args)
    {
        Sub s1 = new Sub();
        System.out.println( s1.toString() );

        // Serialize the object and save it to a file
        try {
            FileOutputStream fout = new FileOutputStream("object.dat");
            ObjectOutputStream oos = new ObjectOutputStream(fout);
            oos.writeObject( s1 );
            oos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        Sub s2 = null;
        // Load the file and deserialize the object
        try {
            FileInputStream fin = new FileInputStream("object.dat");
            ObjectInputStream ois = new ObjectInputStream(fin);
            s2 = (Sub) ois.readObject();
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println( s2.toString() );
    }
}

サブでメインを1回実行して、オブジェクトを作成および保存します。次に、BaseクラスのserialVersionUIDを変更し、オブジェクトを保存するmainの行をコメントアウトして(オブジェクトを再度保存しないように、古いオブジェクトをロードするだけです)、再度実行します。これにより、例外が発生します

java.io.InvalidClassException: Base; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
于 2009-05-21T14:50:40.250 に答える
7

はい、一般的に、他のクラスがシリアルIDを必要とするのと同じ理由で、シリアルIDが生成されないようにします。基本的に、シリアライズ可能を実装するクラス(インターフェイスではない)はシリアルバージョンIDを定義する必要があります。そうしないと、同じ.classコンパイルがサーバーとクライアントのJVMにない場合にデシリアライズエラーが発生するリスクがあります。

あなたが何か空想的なことをしようとしているなら、他のオプションがあります。「サブクラスの意図です…」とはどういう意味かわかりません。カスタムシリアル化メソッド(writeObject、readObjectなど)を作成しますか?もしそうなら、スーパークラスを扱うための他のオプションがあります。

参照: http: //java.sun.com/javase/6/docs/api/java/io/Serializable.html

HTHトム

于 2009-05-21T14:53:42.567 に答える
3

serialVersionID実際、行方不明が実際にシリアライゼーションランタイムによって計算される場合、つまりコンパイル時ではない場合、トムのリンクから指摘します

シリアル化可能なクラスが serialVersionUID を明示的に宣言しない場合、シリアル化ランタイムは、クラスのさまざまな側面に基づいて、そのクラスのデフォルトの serialVersionUID 値を計算します...

これにより、JRE のバージョンが異なるため、事態はさらに複雑になります。

于 2014-04-30T14:00:34.157 に答える